|
6505
|
System dev logs, drafts by @SamTheArchitect | Star System dev logs, drafts by @SamTheArchitect | Stardance...
|
SamTheArchitect
|
0
|
107.05
|
0
|
[]
|
[{"post_id": 34618, "ts": "202 [{"post_id": 34618, "ts": "2026-07-25T14:27:31Z", "hours": 12.6883, "text": "Workflow Closure & Collapse orchestrator This feature ensures the git commit history remains clean from wips, and the closure when the development of a requirement is finished remains frictionless by automating git operations such as path finding, worktree and branch deletion. Leaving the workspace clean and ready to restart the workflow again for a new update or extra feature. How this engine works Once the builder has complete the implementation, perform a final commit with all changes implemented and staged When the builder runs the command collapse within the worktree to finish the workflow, Then the engine should: Merge the final commit to the main branch The implementation of the requirement wips are preserved in the final commit squash. The history has only one commit with the wip changes The merge is complete successfully Delete the worktree & branch once the commit is present in the main branch to ensure no data is lost and the req name is availability for future implementations Unlink the symlink connection of the markdown editor for the specific docs folder and link to the main docs tree The engine in action"}, {"post_id": 29472, "ts": "2026-07-16T13:23:05Z", "hours": 11.5917, "text": "Git Wortree Set Up & Spawn Orchestrator New functionalities The spawn command is now connected to the orchestrator in the package.json so that it can later be publish in npm and make it fully global accessible in the developer system by using the -g flag Config changes memory: Every time the system changes the system-config.json the changes are automatically staged and commit so that they are present in the new worktree Testing Created two integration automated test using jest that stress test the spawn engine under different scenarios and flags, implement a cool ghost typist so that no questions arise why testing, since those are handle by the ghost typist and test itself. Performed an e2e test in an isolated enviroment within my computer, finding some bugs and fixing them properly. (The video shows the e2e test in action) Fixes The system faced a config path mismatch when the command was trigger when the worktree was outside of a prefix folder and then moved to it, making the config file ENOENT . e2e test e2e spawn engine in action Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Handle the config-system.json presence if not handle its creation Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Open a VS code instance"}, {"post_id": 27206, "ts": "2026-07-12T15:48:41Z", "hours": 10.3403, "text": "Git Wortree Set Up & Spawn Orchestrator I develop the initial part of the system requirement of a workflow orchestrator that interacts with git and the system files to create a frictionless, fast and intuitive experience when bringing ideas to live. Creating and isolated environment that ensures the change log remains pristine and connected to a specific Requirement artifact and its context and market value. Command and flags The command that triggers the first part of the orchestrator is spawn with a string argument that will be the name of the requirement to implement e.g: req023 . It can be called with different flags to modify the behavior of the orchestrator and achieve different functionalities: --symlink or -s --code or -c Flag Combinations and what it achieves Scenario A: Git Tree Workflow & Symlink Connection To The Markdown Editor Update Only trigger the command with the -s flag: Creates a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Scenario B: Git Tree Workflow Intialization enhance functionality for VSCode instance & Symlink Connection To The Markdown Editor Update Trigger the command with the -s & -c flag: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Open a VS code instance Scenario C: Git Tree Workflow Initialization enhance functionality for VSCode instance Only trigger the command with the -c flag: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Open a VS code instance Scenario D: Default only worktree creation folder set up Trigger the command without flags: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Challenges To handle the underlying mechanism of git such as the way it manages the links from the main worktree to its linked ones, how to move them without breaking the linkage and how to heal the systme once the main woerktree is moved represent a challenge that involve some hours of debugging, logs, investigation and testing to make it properly set up the initial state of the system and continue with the worktree creation."}, {"post_id": 25089, "ts": "2026-07-09T02:19:03Z", "hours": 20.9244, "text": "Git staging workflow & pristine version control engineering Context of the problem Now that the system is getting to its final shape one of the most important tools it should integrate is git, but how to do it properly to ensure a pristine commit history to understand the project, its progression, what has been implemented and how the project as evolved over time. Also easily look backwards for quickly identification of the implementation details we are looking for. Nor in a messy uncontextualized way but rather having clear context on what are those changes related to, which requisite is being implemented, refactor or updated Managing docs and code within the same repository carries the risk of “micro commit bloat” only small work and temporary struggle that doesn’t carry a significant weight when backward looking in the future fill the commit history. When reviewing you don’t what to see hundreds of micro commits that doesn’t actually inform of a complete feature. I’ve analize the possible architectural decision including: Workspace squashing and isolated staging of wip commits Git worktrees Clean commit guidelines Clean Room Extraction: 2 branches one for the workspace, containing all the wip messy commits. Edge cases But the one that must be picked is the one that adresses the edge cases: Probable cross device synchronization commits that should not be part of the final commit history. Another key edge case is the synchronization of the cloud repository and the conflict it might cause with the overall sync and the atomic commit history. Handling two REQs that modify the same file in different lines Complete vision of the doc files from the markdown renderer The decision The final decision combines some of the previously mention alternatives and discards others but to make it short the solution is to use worktrees, one per requirement implementation and then clean it out, but this also comes with the frictions of having to update the symlink connection to the markdown editor of preference. Visually explained the architecture is in a digrama below Benefits Semantic commits The repository becomes self-documenting. Generating >“release notes”, “architectural change log” or revising >the project evolution becomes a mathematical query: git log --grep=\"^type\" Structural Bracket Identifier This makes it possible to audit the overall evolution of a >specific requirement implementation or architectural >decision over the project life by using git log --grep=\"[ID]\" . Ease the debugging process and version control >navigation. Git-Tree Concurrent file work history collapse solution: by using >the git-tree the edge case of losing track of multi line >edits that belong to different REQs in the same file is >handled gracefully by the work tree capabilities Dashboard blindness solution: Eliminates dashboard >blindness by using the symlink connection Workflow & the custom Script Finding paths to create symlinks, moving trees to a parent folder so the development can began, the squashing of the commits for a clean history and the merge of wortrees to the main branch migth represent minutes of administrative friction. So the implementation of a script that ease the friction parts of the workflow to ensure the developer never gets out of flow due to administrative stuff is a foundational add on to the system."}, {"post_id": 19990, "ts": "2026-07-01T13:49:00Z", "hours": 41.9653, "text": "Automatic Link Connections Refactor Engine This engine ensures there is no need for manually refactoring of links that connect the related files across the project. Simply imagining updating hundreds of broken links when a name or folder is change, that is not acceptable. Also helps reducing the friction when creating connections like thinking the relative path to the file. This way is avoid the debt of having broken links across the traceability system and friction of connecting files is reduce to 0. Implementation Details File mapping Engineer FileSelectionHelper.js which uses a recursive algorithm that serves as a helper method for data collection using node for file path extraction that works as follows: Extracts the root folder directories and all files paths and names storing them in a data structure. Stores them separately creating a distinction between files and folders. Recursively calls itself to scan the directories stored but before deletes the previously scan directory to ensure the algorithm doesn’t fall in an infinite loop. Stops once there are no more directories to scan. Connections Mapping Implement a helper function PathExtractionHelper.js that will take the found files by FileSelectionHelper.js build a map of the artifacts and the files that mention a connection to them. Algorithm behavior: Loop over all the files of the project Reads the file data an check for a connection mention @trace REQ-001 @ If that artifact exist as a key in the data structure it will append the file, and ensure the already stored connections are not lost Otherwise it will append the first file and create the key Traceability Pipeline Class To ensure clean code, concern separation and functionality encapsulation I develop a class that contains methods that make possible the traceability engine. Methods capabilities: Find artifact path in the project folder Classify artifact connections in different areas Build a markdown table with those connections classification and its relative path to the current artifact ready to navigate by a click from any markdown rendering engine (this ensures the builder can easily open and navigate through the artifact related files, probably implementing what the artifact states) Write the markdown table to a specific artifact.md file Engine execution Once the separated functionalities are encapsulated in its methods and helpers the engine must be orchestrated to provided the expected behavior for this the AutoLinkRefactorExecutionThread.js ensures the execution works as intended leveraging the tools available to ensure the acceptance criteria expected outcome is fulfilled. Testing To ensure system integrity this implementation includes 2 test suits: 6 unit tests for the standalone methods and helpers 1 integration test that ensures that the orchestration of the standalone pieces provide the expected output."}, {"post_id": 11268, "ts": "2026-06-18T13:00:02Z", "hours": 9.5367, "text": "CORE FEATURES Engineer the requirements structure & artifacts including: Kanban Board: How data can be accessed from the requisite Kanban board to increase productivity and maintain a wip (work in progress) of one at the time while visualizing the status and priority of each requisite. Artifacts: Create templates for each of the requisite note artifacts: User Stories, acceptance criteria, Analytical breakdown (Operational procedure to guide problem solving ). Traceability properties: Define the yaml properties for the REQ artifact to ensure traceability form the kanban and the Maps of content dashboard. Define a symlink connection usage from the markdown editor to the project folder with the git system Engineer the architectural decision records structure and artifacts including: Kanban Board: How data can be accessed from the ADRs Kanban board visualize decisions that are pending, approved or depracated Artifacts: Create templates for each of the requisite note artifacts Traceability properties: Define the yaml properties for the ADR artifact to ensure traceability from the kanban and the Maps of content dashboard. Created a central MOC dashboard that maps automatically ADRs, REQs and Vertical slicing diagrams. Includes also an architectural diagram that gives a big picture of how the system behaves."}]...
|
Title: System dev logs, drafts by @SamTheArchitect Title: System dev logs, drafts by @SamTheArchitect | Stardance
Devlogs:
CORE FEATURES Engineer the requirements structure & artifacts including: Kanban Board: How data can be accessed from the requisite Kanban board to increase productivity and maintain a wip (work in progress) of one at the time while visualizing the status and priority of each requisite. Artifacts: Create templates for each of the requisite note artifacts: User Stories, acceptance criteria, Analytical breakdown (Operational procedure to guide problem solving ). Traceability properties: Define the yaml properties for the REQ artifact to ensure traceability form the kanban and the Maps of content dashboard. Define a symlink connection usage from the markdown editor to the project folder with the git system Engineer the architectural decision records structure and artifacts including: Kanban Board: How data can be accessed from the ADRs Kanban board visualize decisions that are pending, approved or depracated Artifacts: Create templates for each of the requisite note artifacts Traceability properties: Define the yaml properties for the ADR artifact to ensure traceability from the kanban and the Maps of content dashboard. Created a central MOC dashboard that maps automatically ADRs, REQs and Vertical slicing diagrams. Includes also an architectural diagram that gives a big picture of how the system behaves.
Automatic Link Connections Refactor Engine This engine ensures there is no need for manually refactoring of links that connect the related files across the project. Simply imagining updating hundreds of broken links when a name or folder is change, that is not acceptable. Also helps reducing the friction when creating connections like thinking the relative path to the file. This way is avoid the debt of having broken links across the traceability system and friction of connecting files is reduce to 0. Implementation Details File mapping Engineer FileSelectionHelper.js which uses a recursive algorithm that serves as a helper method for data collection using node for file path extraction that works as follows: Extracts the root folder directories and all files paths and names storing them in a data structure. Stores them separately creating a distinction between files and folders. Recursively calls itself to scan the directories stored but before deletes the previously scan directory to ensure the algorithm doesn’t fall in an infinite loop. Stops once there are no more directories to scan. Connections Mapping Implement a helper function PathExtractionHelper.js that will take the found files by FileSelectionHelper.js build a map of the artifacts and the files that mention a connection to them. Algorithm behavior: Loop over all the files of the project Reads the file data an check for a connection mention @trace REQ-001 @ If that artifact exist as a key in the data structure it will append the file, and ensure the already stored connections are not lost Otherwise it will append the first file and create the key Traceability Pipeline Class To ensure clean code, concern separation and functionality encapsulation I develop a class that contains methods that make possible the traceability engine. Methods capabilities: Find artifact path in the project folder Classify artifact connections in different areas Build a markdown table with those connections classification and its relative path to the current artifact ready to navigate by a click from any markdown rendering engine (this ensures the builder can easily open and navigate through the artifact related files, probably implementing what the artifact states) Write the markdown table to a specific artifact.md file Engine execution Once the separated functionalities are encapsulated in its methods and helpers the engine must be orchestrated to provided the expected behavior for this the AutoLinkRefactorExecutionThread.js ensures the execution works as intended leveraging the tools available to ensure the acceptance criteria expected outcome is fulfilled. Testing To ensure system integrity this implementation includes 2 test suits: 6 unit tests for the standalone methods and helpers 1 integration test that ensures that the orchestration of the standalone pieces provide the expected output.
Git staging workflow & pristine version control engineering Context of the problem Now that the system is getting to its final shape one of the most important tools it should integrate is git, but how to do it properly to ensure a pristine commit history to understand the project, its progression, what has been implemented and how the project as evolved over time. Also easily look backwards for quickly identification of the implementation details we are looking for. Nor in a messy uncontextualized way but rather having clear context on what are those changes related to, which requisite is being implemented, refactor or updated Managing docs and code within the same repository carries the risk of “micro commit bloat” only small work and temporary struggle that doesn’t carry a significant weight when backward looking in the future fill the commit history. When reviewing you don’t what to see hundreds of micro commits that doesn’t actually inform of a complete feature. I’ve analize the possible architectural decision including: Workspace squashing and isolated staging of wip commits Git worktrees Clean commit guidelines Clean Room Extraction: 2 branches one for the workspace, containing all the wip messy commits. Edge cases But the one that must be picked is the one that adresses the edge cases: Probable cross device synchronization commits that should not be part of the final commit history. Another key edge case is the synchronization of the cloud repository and the conflict it might cause with the overall sync and the atomic commit history. Handling two REQs that modify the same file in different lines Complete vision of the doc files from the markdown renderer The decision The final decision combines some of the previously mention alternatives and discards others but to make it short the solution is to use worktrees, one per requirement implementation and then clean it out, but this also comes with the frictions of having to update the symlink connection to the markdown editor of preference. Visually explained the architecture is in a digrama below Benefits Semantic commits The repository becomes self-documenting. Generating >“release notes”, “architectural change log” or revising >the project evolution becomes a mathematical query: git log --grep="^type" Structural Bracket Identifier This makes it possible to audit the overall evolution of a >specific requirement implementation or architectural >decision over the project life by using git log --grep="[ID]" . Ease the debugging process and version control >navigation. Git-Tree Concurrent file work history collapse solution: by using >the git-tree the edge case of losing track of multi line >edits that belong to different REQs in the same file is >handled gracefully by the work tree capabilities Dashboard blindness solution: Eliminates dashboard >blindness by using the symlink connection Workflow & the custom Script Finding paths to create symlinks, moving trees to a parent folder so the development can began, the squashing of the commits for a clean history and the merge of wortrees to the main branch migth represent minutes of administrative friction. So the implementation of a script that ease the friction parts of the workflow to ensure the developer never gets out of flow due to administrative stuff is a foundational add on to the system.
Git Wortree Set Up & Spawn Orchestrator I develop the initial part of the system requirement of a workflow orchestrator that interacts with git and the system files to create a frictionless, fast and intuitive experience when bringing ideas to live. Creating and isolated environment that ensures the change log remains pristine and connected to a specific Requirement artifact and its context and market value. Command and flags The command that triggers the first part of the orchestrator is spawn with a string argument that will be the name of the requirement to implement e.g: req023 . It can be called with different flags to modify the behavior of the orchestrator and achieve different functionalities: --symlink or -s --code or -c Flag Combinations and what it achieves Scenario A: Git Tree Workflow & Symlink Connection To The Markdown Editor Update Only trigger the command with the -s flag: Creates a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Scenario B: Git Tree Workflow Intialization enhance functionality for VSCode instance & Symlink Connection To The Markdown Editor Update Trigger the command with the -s & -c flag: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Open a VS code instance Scenario C: Git Tree Workflow Initialization enhance functionality for VSCode instance Only trigger the command with the -c flag: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Open a VS code instance Scenario D: Default only worktree creation folder set up Trigger the command without flags: Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Challenges To handle the underlying mechanism of git such as the way it manages the links from the main worktree to its linked ones, how to move them without breaking the linkage and how to heal the systme once the main woerktree is moved represent a challenge that involve some hours of debugging, logs, investigation and testing to make it properly set up the initial state of the system and continue with the worktree creation.
Git Wortree Set Up & Spawn Orchestrator New functionalities The spawn command is now connected to the orchestrator in the package.json so that it can later be publish in npm and make it fully global accessible in the developer system by using the -g flag Config changes memory: Every time the system changes the system-config.json the changes are automatically staged and commit so that they are present in the new worktree Testing Created two integration automated test using jest that stress test the spawn engine under different scenarios and flags, implement a cool ghost typist so that no questions arise why testing, since those are handle by the ghost typist and test itself. Performed an e2e test in an isolated enviroment within my computer, finding some bugs and fixing them properly. (The video shows the e2e test in action) Fixes The system faced a config path mismatch when the command was trigger when the worktree was outside of a prefix folder and then moved to it, making the config file ENOENT . e2e test e2e spawn engine in action Create a folder with the prefix if not previously created and move the main worktree dir and other worktrees present there Handle the config-system.json presence if not handle its creation Create a new worktree with the artifact in lowercase as name and branch to work within the folder with the project identifier prefix Connect the docs of the new worktree to the folder in the markdown editor Open a VS code instance
Workflow Closure & Collapse orchestrator This feature ensures the git commit history remains clean from wips, and the closure when the development of a requirement is finished remains frictionless by automating git operations such as path finding, worktree and branch deletion. Leaving the workspace clean and ready to restart the workflow again for a new update or extra feature. How this engine works Once the builder has complete the implementation, perform a final commit with all changes implemented and staged When the builder runs the command collapse within the worktree to finish the workflow, Then the engine should: Merge the final commit to the main branch The implementation of the requirement wips are preserved in the final commit squash. The history has only one commit with the wip changes The merge is complete successfully Delete the worktree & branch once the commit is present in the main branch to ensure no data is lost and the req name is availability for future implementations Unlink the symlink connection of the markdown editor for the specific docs folder and link to the main docs tree The engine in action...
|
1792576142.8627796
|
1793180942.8627796
|
|
45237
|
Guitar Game by @Nele | Stardance
|
Nele
|
0
|
106.21
|
0
|
[]
|
[{"post_id": 80477, "ts": "202 [{"post_id": 80477, "ts": "2026-10-17T19:43:21Z", "hours": 2.3531, "text": "I finished level 1 to 3 with the 7 Nation Army riff and of course redisined level 1 to 3 so that the obstacles match the rithm of seven Nation Army. I also started with a level with chrods, but first I want to make a chord catalog where you can look how to play each chord you need for the level or, respectively the song. Here is one of the levels preview (it’s level 3) :"}, {"post_id": 79988, "ts": "2026-10-15T19:17:55Z", "hours": 2.3706, "text": "Heyooo, as I promised or said I created three levels for a riff to a real song. It’s the well known seven nation army riff (: The first level has just the notes you need for the riff, already in the correct order, but you have muchhh time to play them, so you get familar to where they are on your guitar. I have already plans to desing level two and three, but I have to sleep. So I will do it tomorrow or another day. I am very exited to do this and later show it to you! Here is the array with the obstacles for level one, you can see which frets and strings I used for the riff:"}, {"post_id": 79635, "ts": "2026-10-14T19:28:10Z", "hours": 0.8972, "text": "Hello I changed the size so it is more playable on phone and made a preview to every level which is personal designed for each level… or it will be. I also testet a lot and made preview screenshots. Then I had the idea to use popular guitar riffs for my levels, so that you can actually play a song in the end, which I think would be muchhhh cooler than just some notes. I hope this will work!!!!! I don’t know what to show so here is one of the preview screenshots"}, {"post_id": 79398, "ts": "2026-10-13T20:07:34Z", "hours": 2.5567, "text": "I worked on the desert theme an nearly finished it, but I wantet to change how the game displays the notes and did it. But at first I ran into many issues. I desided to show one here. I first completely destroyed my layout and had to figure out what hapend and how to fix it. In the end I did it and also designed level 4! So here my broken layout…"}, {"post_id": 79132, "ts": "2026-10-12T19:40:18Z", "hours": 1.6378, "text": "I got the design showing up and it looks okay for now. Tomorrow I will try to get cleaner animations. I also aranged level 2 and 3. And did a looottt of testing"}, {"post_id": 78830, "ts": "2026-10-11T18:23:50Z", "hours": 1.2314, "text": "I’m designing my levels at the moment and rearanged level 1. Then I wanted to add different themes… I started with a desert theme. I implemented it just like my arcade theme but it did not really work and I can’t tell why… But I guess I will figure it out"}, {"post_id": 78278, "ts": "2026-10-10T08:18:20Z", "hours": 3.1233, "text": "I finished the chord detection!!! But I’m not satisfied because it does not work as good as I want it. You have to play the chords very clear and loud so you need to use an amplifier if you play on electric guitar. I wanted the detection also to detect quiet chords, but I just don’t get it so I added this information at the beginning. At least it does work :)"}, {"post_id": 77149, "ts": "2026-10-05T19:43:31Z", "hours": 1.2861, "text": "Began to implement a chord detection, to extend my existing note detection, but ran in tooo many problems so I will continue tomorrow. And I designed one level (level 11) that means I rearanged the obstacles."}, {"post_id": 76795, "ts": "2026-10-04T16:11:22Z", "hours": 4.2256, "text": "Stardance has extended, so I took the time to build some small features, like a loading screen, which is displayed when starting the game so thath the images can load before and not while playing. I also added a function which brings the game on full screen when starting and flips the screen if youre playing on phone (works with google on my phone). Annddd I added a note which only pops up, if you open the game for the first time (you can see it in the screenshot). I also cleaned the code, it’s the worst work and nobody really notices…"}, {"post_id": 75336, "ts": "2026-09-29T19:33:00Z", "hours": 9.4228, "text": "I made my game ready to ship. It is now fully playable!! I’ve added some basic funktions… You can take a look at the full game in this video!!! I will add some levels to round it up and then finally ship it"}, {"post_id": 74429, "ts": "2026-09-27T11:21:34Z", "hours": 8.7761, "text": "Hellooooo, I created a pause and a startscreen menu (: I also build the first level!"}, {"post_id": 73575, "ts": "2026-09-25T12:45:01Z", "hours": 9.9753, "text": "I tinkered a bit with th enote detection, but is hasn’t really improved much. The most visible result is probalby that I’ve improved - or at least changed - the design. I’m currently working on a pause menu and have laid the groundwork to create a tutorial soon. I definitely need to lock in over the next few days because I still have so many ideas - even though I have a math exam in four days and haven’t done a thing for it yet. But come on, it’s only math."}, {"post_id": 68754, "ts": "2026-09-15T17:54:56Z", "hours": 2.9547, "text": "I’ve tidied up my code a bit - adding comments and organizing it into logical sections. I still habe a lot of work ahead of me there, but once that’s done, I’ll ve albe to continue working effectively."}, {"post_id": 67615, "ts": "2026-09-13T19:20:56Z", "hours": 10.7439, "text": "Hey there! I’ve expanded the game in a few small ways and focused ont the basic design - adding a few animations here and there. And acuteally (to my surprise) everything is finally working so far. So, here is a video at last!"}, {"post_id": 61556, "ts": "2026-09-04T15:06:18Z", "hours": 10.1756, "text": "I’ve made the game largely responsive now and as you can see I experimented a bit with the backgrounds. I’ve added two more types of obstacles to provide more variety, but unfortunately, I still don’t habe a fully functional level ready - so, once again, just a screenshot:"}, {"post_id": 58729, "ts": "2026-08-31T08:45:12Z", "hours": 10.0539, "text": "I intergrated the note recognition with the game logic and my first test run was succesful: the player jumps when the right note is played at the right time and crashes into the obstacle if not. I also experimented with a few simple designs and had the idea of making the game responsive - I messed that up a bit, but I#m fixing it. Unfortunately, the game logic isn’t working quite right again yet, so here is just a screenshot"}, {"post_id": 55651, "ts": "2026-08-27T16:40:53Z", "hours": 16.0339, "text": "I’ve been working on pitch detection and ran into a few issues, but my program can now identify which string is being played based on its frequency. Unfortunately, it insn’t precise yet, because some strings share the same frequency as other strings at certain frets. Nevertheless, you can see it in my console here!"}, {"post_id": 51895, "ts": "2026-08-21T19:55:44Z", "hours": 8.3889, "text": "I created the fundamentals for my game and also a first very very basic animation"}]...
|
Title: Guitar Game by @Nele | Stardance
Devlogs:
Title: Guitar Game by @Nele | Stardance
Devlogs:
I created the fundamentals for my game and also a first very very basic animation
I’ve been working on pitch detection and ran into a few issues, but my program can now identify which string is being played based on its frequency. Unfortunately, it insn’t precise yet, because some strings share the same frequency as other strings at certain frets. Nevertheless, you can see it in my console here!
I intergrated the note recognition with the game logic and my first test run was succesful: the player jumps when the right note is played at the right time and crashes into the obstacle if not. I also experimented with a few simple designs and had the idea of making the game responsive - I messed that up a bit, but I#m fixing it. Unfortunately, the game logic isn’t working quite right again yet, so here is just a screenshot
I’ve made the game largely responsive now and as you can see I experimented a bit with the backgrounds. I’ve added two more types of obstacles to provide more variety, but unfortunately, I still don’t habe a fully functional level ready - so, once again, just a screenshot:
Hey there! I’ve expanded the game in a few small ways and focused ont the basic design - adding a few animations here and there. And acuteally (to my surprise) everything is finally working so far. So, here is a video at last!
I’ve tidied up my code a bit - adding comments and organizing it into logical sections. I still habe a lot of work ahead of me there, but once that’s done, I’ll ve albe to continue working effectively.
I tinkered a bit with th enote detection, but is hasn’t really improved much. The most visible result is probalby that I’ve improved - or at least changed - the design. I’m currently working on a pause menu and have laid the groundwork to create a tutorial soon. I definitely need to lock in over the next few days because I still have so many ideas - even though I have a math exam in four days and haven’t done a thing for it yet. But come on, it’s only math.
Hellooooo, I created a pause and a startscreen menu (: I also build the first level!
I made my game ready to ship. It is now fully playable!! I’ve added some basic funktions… You can take a look at the full game in this video!!! I will add some levels to round it up and then finally ship it
Stardance has extended, so I took the time to build some small features, like a loading screen, which is displayed when starting the game so thath the images can load before and not while playing. I also added a function which brings the game on full screen when starting and flips the screen if youre playing on phone (works with google on my phone). Annddd I added a note which only pops up, if you open the game for the first time (you can see it in the screenshot). I also cleaned the code, it’s the worst work and nobody really notices…
Began to implement a chord detection, to extend my existing note detection, but ran in tooo many problems so I will continue tomorrow. And I designed one level (level 11) that means I rearanged the obstacles.
I finished the chord detection!!! But I’m not satisfied because it does not work as good as I want it. You have to play the chords very clear and loud so you need to use an amplifier if you play on electric guitar. I wanted the detection also to detect quiet chords, but I just don’t get it so I added this information at the beginning. At least it does work :)
I’m designing my levels at the moment and rearanged level 1. Then I wanted to add different themes… I started with a desert theme. I implemented it just like my arcade theme but it did not really work and I can’t tell why… But I guess I will figure it out
I got the design showing up and it looks okay for now. Tomorrow I will try to get cleaner animations. I also aranged level 2 and 3. And did a looottt of testing
I worked on the desert theme an nearly finished it, but I wantet to change how the game displays the notes and did it. But at first I ran into many issues. I desided to show one here. I first completely destroyed my layout and had to figure out what hapend and how to fix it. In the end I did it and also designed level 4! So here my broken layout…
Hello I changed the size so it is more playable on phone and made a preview to every level which is personal designed for each level… or it will be. I also testet a lot and made preview screenshots. Then I had the idea to use popular guitar riffs for my levels, so that you can actually play a song in the end, which I think would be muchhhh cooler than just some notes. I hope this will work!!!!! I don’t know what to show so here is one of the preview screenshots
Heyooo, as I promised or said I created three levels for a riff to a real song. It’s the well known seven nation army riff (: The first level has just the notes you need for the riff, already in the correct order, but you have muchhh time to play them, so you get familar to where they are on your guitar. I have already plans to desing level two and three, but I have to sleep. So I will do it tomorrow or another day. I am very exited to do this and later show it to you! Here is the array with the obstacles for level one, you can see which frets and strings I used for the riff:
I finished level 1 to 3 with the 7 Nation Army riff and of course redisined level 1 to 3 so that the obstacles match the rithm of seven Nation Army. I also started with a level with chrods, but first I want to make a chord catalog where you can look how to play each chord you need for the level or, respectively the song. Here is one of the levels preview (it’s level 3) :...
|
1792615977.0897655
|
1793220777.0897655
|
|
7472
|
rumi by @subhansh | Stardance
|
|
1
|
106.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-10T07:38:59Z", "hours": 106.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "rumi - research unified machine intelligence… rumi is an actual autonomous AI scientist designed to discover, not just describe. Powered by a 22 phase, 2 tracks scientific discovery pipeline, RUMI analyzes research literature, builds knowledge representations, identifies gaps in existing explanations, generates novel hypotheses, constructs mathematical and causal models, produces falsifiable predictions, and evaluates competing theories through automated scientific review. Operating across 17 domains, RUMI is built as a general-purpose discovery engine whose objective is to accelerate human research by systematically exploring explanations that may not yet exist in the literature while maintaining transparency, critique, and testability throughout the discovery process. NOTE :- rumi still cant do end to end novel discoveries on her own but she can provide novel ideas with grounded mechanisms and derivations and stronger the reasoning of a model = better results from rumi.. that said… once i get my hands on a frontier llm ill plug it into rumi and develop her more Proof that rumi works :- rumi has helped me publish 1 peer reviewed research paper on analytical number theory (DOI :- 10.5281/zenodo.21107958)", "repo": "https://github.com/subhansh-dev/rumi", "demo": "https://rumi-nu.vercel.app"}]...
|
[{"post_id": 11764, "ts": "202 [{"post_id": 11764, "ts": "2026-06-19T04:39:49Z", "hours": 16.0183, "text": "rumi-Devlog #9 🍓😺✌ today was mostly spent making RUMI faster because some runs were taking an absolutely stupid amount of time 😭 provider stack changes spent a while profiling the provider chain and found a few cursed bottlenecks. disabled Fireworks (credits died, every failed request was wasting ~90s) switched GLM routing to Kimi K2.6 via a second NVIDIA key tested Cerebras-first vs NVIDIA-first routing results were funny: Cerebras = ~2s/call but discoveries averaged around C grade NVIDIA = ~65s/call but much stronger reports so now different parts of the pipeline use different providers depending on the task. phase 6.5 speedup equation generation was committing crimes. rewrote the whole thing to run in parallel (6 workers). went from: ~16 min to ~1 min for a typical 15 mechanism loop. also finally fixed the legendary: 0/15 equations generated bug 😺🍓 literature search all literature sources now fetch concurrently: arXiv PubMed CrossRef OpenAlex etc runtime dropped from ~2 mins to ~64 seconds. RUMI TUI probably my favourite thing from today. built a proper Textual-based TUI so i can actually see what RUMI is doing instead of staring at a terminal for 10 hours. added: real-time phase tracking live agent status brain module dashboard discovery controls /brain /status /dream /memory /hypothesis also fixed a bunch of broken brain module APIs that were pretending to work 💀 random bug of the day RUMI was occasionally turning english into ancient cursed language and generating stuff like: withinamy instead of actual words. fixed topic truncation so it now cuts at word boundaries. current state provider stack healthier equation generation WAY faster literature search faster TUI finally usable brain modules actually verified at boot still spending most of my life waiting for discovery runs to finish though 🥀"}, {"post_id": 9228, "ts": "2026-06-15T14:33:23Z", "hours": 23.0847, "text": "rumi-Devlog #8 🍓 Current status: rumis smarter, my codebase survived, and my sanity is questionable 💔 A huge part of this session wasn’t actually spent improving discovery quality. It was spent improving everything around RUMI. As RUMI’s discovery pipeline keeps getting bigger, debugging has become a nightmare. Reading raw JSON reports, searching through logs, and manually inspecting hundreds of entities was getting painful. So I built a full visualization and monitoring system for RUMI. The dashboard can now visualize: discovery reports theory competitions adversarial testing results predictions refinement stages scoring breakdowns knowledge graphs paper collections hypothesis memory all from a single interface. Knowledge Graph Visualization One thing I’ve wanted for a while was being able to actually SEE what RUMI was discovering. Not read it. See it. So I built an interactive graph explorer using vis.js. Every entity type gets its own visual identity. Nodes glow based on type. Edges scale with confidence. Hovering shows metadata, paper counts, and relationships. The graph uses ForceAtlas physics and overlap avoidance to make large discovery graphs easier to navigate. Watching hundreds of concepts connect together is honestly way more useful than reading raw graph dumps. 🥀 Discovery Report Explorer RUMI reports have become massive. Some are hundreds of kilobytes. Some are over a thousand lines. Reading those manually sucks. So I built dedicated views for: theory competition adversarial evaluation predictions scoring derivations peer review refinement stages which makes analyzing runs significantly easier. Provider Stack Surgery 💔 While testing the new recurrent architecture I discovered a huge bottleneck. Xiaomi MiMo. It was slow. Constantly rate limiting. Burning through provider chains. And starving downstream phases. This turned out to be the reason molecule generation kept randomly failing. So MiMo got removed from the routing stack. After testing 17 API keys across all providers: 13 healthy 4 problematic Current routing stack includes: NVIDIA DeepSeek Kimi K2.6 Cerebras GPT-OSS-120B Groq Gemini Fireworks Still chasing down some timeout and rate limit issues but overall the stack is way healthier now. Discovery Testing Used the upgraded architecture to stress test RUMI on several difficult domains. One of the most interesting runs was Molecular Glue Drug Discovery. Current run stats: 16 hidden variables 15 mechanisms per loop 7 predictions multiple adversarial survivors recurrent refinement loops enabled The architecture is definitely producing stronger outputs than before. meow meow meow"}, {"post_id": 7717, "ts": "2026-06-12T21:37:49Z", "hours": 19.0981, "text": "rumi-Devlog #7 🍓 This was probably one of the most frustrating and important RUMI development sessions so far. Most people only see the final discovery reports. They don’t see the chaos that happens before RUMI can generate a single theory. And trust me, there was a lot of chaos. 💔 Bug Fixes, Bug Fixes, More Bug Fixes I started this session thinking I’d make a few improvements and continue testing. That did not happen. RUMI’s architecture has reached a point where changing one thing breaks three others. Every time I fixed 3 bugs, another 5 appeared from somewhere else. At one point I genuinely crashed out because every run ended with a new issue that didn’t even exist before. It felt like: fix_bug() spawn_more_bugs(count=5) Turns out there’s a reason people say: “If it’s working, don’t touch it.” Unfortunately I touched it. A lot. 🥀 The Problem Even though RUMI was producing interesting discoveries, I still wasn’t satisfied. The reports were often interesting, creative, and sometimes novel, but they still felt too generic. The pipeline would generate a theory, evaluate it once, pick a winner, and move on. I wanted RUMI to spend more time refining ideas instead of treating every discovery as a one-shot attempt. Falling Into The OpenMythos Rabbit Hole While researching I came across OpenMythos, a community attempt to reverse engineer Anthropic’s rumored Mythos architecture. Nobody actually knows how Mythos works, but the community has proposed several reasoning patterns that might explain Claude-style outputs. I spent hours reading through it asking myself: “What parts of this could actually work inside RUMI?” Not copying. Adapting. The Biggest Change I’ve Ever Made To RUMI 🥀 One idea stood out immediately: recurrent reasoning loops. Before: Mechanisms ↓ Predictions ↓ Theory Competition ↓ Winner One pass. One shot. If mechanism generation was weak, everything downstream became weak too. So I rebuilt a huge section of the pipeline. Now RUMI performs a 3-stage recurrent refinement process: Loop 1 — Exploration Maximum creativity Maximum diversity Broad theory generation Loop 2 — Refinement Survivors re-enter the pipeline Focus on evidence, consistency, and mechanism quality Loop 3 — Convergence Lowest creativity Highest rigor Final selection of the strongest explanation Instead of living or dying from a single generation pass, theories now get multiple opportunities to evolve. Preventing Theory Drift Another idea I adapted was evidence grounding injection. Recursive systems often suffer from theory drift, where ideas slowly become disconnected from the evidence that originally generated them. To prevent this, every refinement loop continuously receives: Literature evidence Contradictions Knowledge gaps Observed anomalies This keeps discoveries grounded instead of drifting into fantasy. Smarter Computation I also added convergence-aware halting. Not every scientific problem deserves the same amount of computation. Some topics converge quickly while others require deeper exploration. RUMI can now monitor improvements between loops and eventually stop refining once discoveries begin stabilizing. lwk so much happened in these last 17hrs that i cant even include everything in here cause of the word limit 😭🥀"}, {"post_id": 6459, "ts": "2026-06-10T21:25:00Z", "hours": 15.2386, "text": "rumi - Devlog #6 June 11, 2026 so yea… pulled an all nighter for this one 🥀 most of the work this time wasn’t adding entirely new systems. it was stress testing RUMI hard enough to find where the architecture starts breaking. and honestly i found a lot more than i expected. Track B Architecture Improvements spent a lot of time refining Track B after the initial curiosity pipeline integration. instead of just generating curiosity questions, it now runs through much more of the actual discovery stack. lots of internal changes here that don’t really show up visually but massively affect the quality of the final reports. 💔 Constraint Pipeline Fix found a pretty nasty issue where parts of the generated curiosity constraints weren’t making it all the way through the pipeline. after fixing it, the results became immediately obvious. latest dual-track run: Track A Unique Theories: 9 Track B Unique Theories: 8 Shared Theories: 0 which is honestly one of the strongest signals i’ve seen so far that the dual-track system is actually working as intended. both tracks are now exploring completely different hypothesis spaces instead of converging on the same ideas. Claude Fable 5 Experiment managed to get temporary access to Claude Fable 5 and immediately decided to throw RUMI at it. before i could even test it though… the integration broke 💔 spent a while fixing provider compatibility issues and getting everything working again. eventually got a discovery run started on: What happens to information when it crosses a black hole event horizon? Fable managed to reach roughly Phase 8.5 before the free trial looked at RUMI’s request count and basically said: aight imma head out 😭 What Fable Revealed this ended up being way more valuable than i expected. while comparing Fable’s outputs with the models i normally run, i noticed a massive difference. most models tend to generate: Hidden Variable ↓ Mechanism Description ↓ Prediction Fable was generating: Hidden Variable ↓ Mechanism ↓ Equation ↓ Parameter Extraction ↓ Derivation ↓ Numerical Validation ↓ Prediction actual equations. actual variables. actual derivation chains. actual numerical checks. 🥀 Switching Back To MiMo after the Fable credits died, i moved everything back to MiMo and started comparing outputs. and that’s when another weakness became obvious. the pipeline itself wasn’t failing. MiMo simply wasn’t producing the mathematical depth needed for the mechanism stage. which means the current bottleneck isn’t discovery anymore. it’s mathematical formalization. Mathematical Formalization Architecture one of the most interesting things i noticed while testing Claude Fable 5 was how differently it handled mechanism generation. most models would generate something like: Hidden Variable ↓ Mechanism Description ↓ Prediction while Fable was generating: Hidden Variable ↓ Mechanism ↓ Equation ↓ Parameter Extraction ↓ Derivation ↓ Numerical Validation ↓ Prediction and honestly that immediately exposed one of RUMI’s biggest weaknesses. theories and mechanisms were already being generated. the math wasn’t. so instead of just complaining about it, i started redesigning the mechanism pipeline around that pattern. RUMI now has the foundations for a much more quantitative discovery process where mechanisms aren’t just descriptions anymore, which is lwk tuff ig 🥀✌ equations variables derivations parameter extraction numerical validation Switching Back To MiMo 🥀 after Fable ran out of credits i moved everything back to MiMo and started testing the updated architecture and still doing it cause mimo is like hella slow bruh normally umi takes upto 30-40 mins but now with mimo shes taking aorund 2hr 30mins 💔"}, {"post_id": 5243, "ts": "2026-06-08T23:06:33Z", "hours": 10.65, "text": "Devlog #5 — RUMI Dual-Track Architecture so as yall know yesterday i finished adding the curiosity pipeline (wait… you dont know about this? naaa💔go read yesterday’s devlog >:3…WUT ? GO RN) but yea that was mostly just the foundation today was about actually refining it and wiring it into the rest of RUMI basically i ended up bringing a lot of the Track A discovery pipeline into Track B too because like… why wouldnt i 😭 not just straight up copy-pasting it though because then both tracks would end up doing the same thing instead i reused parts of the architecture while keeping the curiosity systems separate the biggest addition was making the generated curiosity constraints actually flow into the discovery process itself which sounds simple until you spend half the day finding out they werent actually being propagated through the pipeline properly 💔 and then came the debugging arc 😭 DNS resolution failures causing discovery runs to randomly die 😾 (like wdym rumi requested for more papers and data and dns forgetting that internet exists) curiosity constraints not propagating into the pipeline😫 Semantic Scholar 429 rate limits 🥀 Gemini 503 errors 😢 free-tier rate limits everywhere (she makes like 6-7k requests in one run )😺🥀 and somehow RUMI has become so LLM hungry that i had to run her on 13 API keys across 3 different providers just to keep discovery sessions alive 😭 (lwk running on hope and sum duct tape 🥀🥀) there was genuinely a point where i was about to crash out because providers kept rate limiting, APIs were dying, runs were hanging, and everything was fighting me at once 💔🥀😭 but after all that RUMI finally completed a full dual-track discovery run topic: “Why does the universe expand faster than expected?” results: Track A Winner → Scale-Dependent Effective Gravity Track B Winner → Temporal Vacuum Shear Framework and this is where things got interesting Track A and Track B finished with: 0 shared theories <–(🙀) different winners different hidden variables different contradiction sets different mechanisms 0 runtime errors RUMI generated: 17 theories 30 mechanisms 22 hidden variables 12 contradictions 12 predictions from a single discovery session 😭 and honestly the most important number isnt the score its this: Shared Theories: 0 because it means Track B isnt just making a slightly remixed version of Track A anymore both tracks started from the same question, same literature, same knowledge base, and still ended up exploring completely different hypothesis spaces which is pretty much the entire reason i built the curiosity system in the first place 😭🥀 still more work to do, but today feels like one of the biggest architecture milestones for RUMI so far💔🥀 lwk gonna try to improve GFlowNets tmrw here’s the updated pipeline diagram :-"}, {"post_id": 4578, "ts": "2026-06-07T22:28:00Z", "hours": 9.3764, "text": "Stardance Devlog #3 June 7, 2026 Today I realized RUMI’s biggest limitation wasn’t math, evidence, reviewers, or the 17-stage pipeline. It was curiosity. For days I’ve been making RUMI better at reading papers, finding gaps, generating hypotheses, scoring theories, and validating ideas, which actually improved her ALLAT… but still something felt missing. Then it hit me. RUMI could analyze research. RUMI could synthesize research. RUMI could critique research. But RUMI never stopped and asked: “Why does this happen at all?” And that’s where most discoveries begin🥀 So today I built Phase 0 — The Curiosity Engine. Before reading papers. Before building knowledge graphs. Before generating mechanisms. RUMI now starts by questioning the problem itself. What could be causing this? What assumptions are we making? What if the accepted explanation is incomplete? What are we not looking at? Basically, RUMI now wonders before she researches😭 The first implementation was a disaster. I merged curiosity directly into the main pipeline and immediately turned the architecture into spaghetti. So I rebuilt it. Now there are two separate paths: Conventional RUMI Reads Analyzes Verifies Curious RUMI Questions Explores Challenges assumptions Both run independently and merge into the final report💔 The funny part is that after building theory tournaments, Bayesian reasoning, evidence systems, mathematical verification, observability checks, and dozens of other modules… The biggest upgrade might have been teaching RUMI something humans learn as children: Curiosity🥀😭 Today’s Progress Phase 0 Curiosity Engine ✅ Dual-Pipeline Architecture ✅ Evidence Extraction Improvements ✅ Observability Checks ✅ Mechanism Completeness Scoring ✅ My Sanity ❌ See you tomorrow. Hopefully before RUMI starts asking questions that create more problems than answers. 🥀💔"}, {"post_id": 3851, "ts": "2026-06-06T22:22:37Z", "hours": 2.2931, "text": "spent basically the whole day inside RUMI’s discovery engine and ngl it was pain 💔 fixed 50+ bugs across the pipeline. some of the biggest ones were: empty hypotheses theory tournament crashing unicode errors on windows graph contamination novelty scoring issues mechanism validation deleting everything 😭 also built a few new systems: math verification engine counterfactual/“what if” hypothesis generation entity enrichment (NASA, PubChem, UniProt, PDB, etc.) better novelty scoring tournament winner override before the fixes, some discoveries were scoring: 0/100 40/100 45/100 after everything: FRB Magnetar: 66/100 (B) KRAS G12D: 65/100 (B) the coolest run today was on Fast Radio Bursts and magnetars. RUMI went through 69 papers, generated new hidden variables, built mechanisms around them, made testable predictions, then tried to destroy its own ideas through adversarial testing. finally it actually felt like the pipeline was working end-to-end instead of randomly exploding lol 😭 still got a long way to go though. biggest weaknesses right now are novelty and mathematical rigor. RUMI is getting better at explaining science, now I need to make her better at finding genuinely new stuff. back to debugging tomorrow frfr 💔🥀😭"}, {"post_id": 3528, "ts": "2026-06-06T14:42:38Z", "hours": 2.1419, "text": "yayaya finallyy finally the basic tui is working and the frontend-backend integration is almost there"}, {"post_id": 2865, "ts": "2026-06-05T18:48:30Z", "hours": 7.7036, "text": "12hr 726mins in and still not finished debugging 💔🥀"}]...
|
Title: rumi by @subhansh | Stardance
Devlogs:
12h Title: rumi by @subhansh | Stardance
Devlogs:
12hr 726mins in and still not finished debugging 💔🥀
yayaya finallyy finally the basic tui is working and the frontend-backend integration is almost there
spent basically the whole day inside RUMI’s discovery engine and ngl it was pain 💔 fixed 50+ bugs across the pipeline. some of the biggest ones were: empty hypotheses theory tournament crashing unicode errors on windows graph contamination novelty scoring issues mechanism validation deleting everything 😭 also built a few new systems: math verification engine counterfactual/“what if” hypothesis generation entity enrichment (NASA, PubChem, UniProt, PDB, etc.) better novelty scoring tournament winner override before the fixes, some discoveries were scoring: 0/100 40/100 45/100 after everything: FRB Magnetar: 66/100 (B) KRAS G12D: 65/100 (B) the coolest run today was on Fast Radio Bursts and magnetars. RUMI went through 69 papers, generated new hidden variables, built mechanisms around them, made testable predictions, then tried to destroy its own ideas through adversarial testing. finally it actually felt like the pipeline was working end-to-end instead of randomly exploding lol 😭 still got a long way to go though. biggest weaknesses right now are novelty and mathematical rigor. RUMI is getting better at explaining science, now I need to make her better at finding genuinely new stuff. back to debugging tomorrow frfr 💔🥀😭
Stardance Devlog #3 June 7, 2026 Today I realized RUMI’s biggest limitation wasn’t math, evidence, reviewers, or the 17-stage pipeline. It was curiosity. For days I’ve been making RUMI better at reading papers, finding gaps, generating hypotheses, scoring theories, and validating ideas, which actually improved her ALLAT… but still something felt missing. Then it hit me. RUMI could analyze research. RUMI could synthesize research. RUMI could critique research. But RUMI never stopped and asked: “Why does this happen at all?” And that’s where most discoveries begin🥀 So today I built Phase 0 — The Curiosity Engine. Before reading papers. Before building knowledge graphs. Before generating mechanisms. RUMI now starts by questioning the problem itself. What could be causing this? What assumptions are we making? What if the accepted explanation is incomplete? What are we not looking at? Basically, RUMI now wonders before she researches😭 The first implementation was a disaster. I merged curiosity directly into the main pipeline and immediately turned the architecture into spaghetti. So I rebuilt it. Now there are two separate paths: Conventional RUMI Reads Analyzes Verifies Curious RUMI Questions Explores Challenges assumptions Both run independently and merge into the final report💔 The funny part is that after building theory tournaments, Bayesian reasoning, evidence systems, mathematical verification, observability checks, and dozens of other modules… The biggest upgrade might have been teaching RUMI something humans learn as children: Curiosity🥀😭 Today’s Progress Phase 0 Curiosity Engine ✅ Dual-Pipeline Architecture ✅ Evidence Extraction Improvements ✅ Observability Checks ✅ Mechanism Completeness Scoring ✅ My Sanity ❌ See you tomorrow. Hopefully before RUMI starts asking questions that create more problems than answers. 🥀💔
Devlog #5 — RUMI Dual-Track Architecture so as yall know yesterday i finished adding the curiosity pipeline (wait… you dont know about this? naaa💔go read yesterday’s devlog >:3…WUT ? GO RN) but yea that was mostly just the foundation today was about actually refining it and wiring it into the rest of RUMI basically i ended up bringing a lot of the Track A discovery pipeline into Track B too because like… why wouldnt i 😭 not just straight up copy-pasting it though because then both tracks would end up doing the same thing instead i reused parts of the architecture while keeping the curiosity systems separate the biggest addition was making the generated curiosity constraints actually flow into the discovery process itself which sounds simple until you spend half the day finding out they werent actually being propagated through the pipeline properly 💔 and then came the debugging arc 😭 DNS resolution failures causing discovery runs to randomly die 😾 (like wdym rumi requested for more papers and data and dns forgetting that internet exists) curiosity constraints not propagating into the pipeline😫 Semantic Scholar 429 rate limits 🥀 Gemini 503 errors 😢 free-tier rate limits everywhere (she makes like 6-7k requests in one run )😺🥀 and somehow RUMI has become so LLM hungry that i had to run her on 13 API keys across 3 different providers just to keep discovery sessions alive 😭 (lwk running on hope and sum duct tape 🥀🥀) there was genuinely a point where i was about to crash out because providers kept rate limiting, APIs were dying, runs were hanging, and everything was fighting me at once 💔🥀😭 but after all that RUMI finally completed a full dual-track discovery run topic: “Why does the universe expand faster than expected?” results: Track A Winner → Scale-Dependent Effective Gravity Track B Winner → Temporal Vacuum Shear Framework and this is where things got interesting Track A and Track B finished with: 0 shared theories <–(🙀) different winners different hidden variables different contradiction sets different mechanisms 0 runtime errors RUMI generated: 17 theories 30 mechanisms 22 hidden variables 12 contradictions 12 predictions from a single discovery session 😭 and honestly the most important number isnt the score its this: Shared Theories: 0 because it means Track B isnt just making a slightly remixed version of Track A anymore both tracks started from the same question, same literature, same knowledge base, and still ended up exploring completely different hypothesis spaces which is pretty much the entire reason i built the curiosity system in the first place 😭🥀 still more work to do, but today feels like one of the biggest architecture milestones for RUMI so far💔🥀 lwk gonna try to improve GFlowNets tmrw here’s the updated pipeline diagram :-
rumi - Devlog #6 June 11, 2026 so yea… pulled an all nighter for this one 🥀 most of the work this time wasn’t adding entirely new systems. it was stress testing RUMI hard enough to find where the architecture starts breaking. and honestly i found a lot more than i expected. Track B Architecture Improvements spent a lot of time refining Track B after the initial curiosity pipeline integration. instead of just generating curiosity questions, it now runs through much more of the actual discovery stack. lots of internal changes here that don’t really show up visually but massively affect the quality of the final reports. 💔 Constraint Pipeline Fix found a pretty nasty issue where parts of the generated curiosity constraints weren’t making it all the way through the pipeline. after fixing it, the results became immediately obvious. latest dual-track run: Track A Unique Theories: 9 Track B Unique Theories: 8 Shared Theories: 0 which is honestly one of the strongest signals i’ve seen so far that the dual-track system is actually working as intended. both tracks are now exploring completely different hypothesis spaces instead of converging on the same ideas. Claude Fable 5 Experiment managed to get temporary access to Claude Fable 5 and immediately decided to throw RUMI at it. before i could even test it though… the integration broke 💔 spent a while fixing provider compatibility issues and getting everything working again. eventually got a discovery run started on: What happens to information when it crosses a black hole event horizon? Fable managed to reach roughly Phase 8.5 before the free trial looked at RUMI’s request count and basically said: aight imma head out 😭 What Fable Revealed this ended up being way more valuable than i expected. while comparing Fable’s outputs with the models i normally run, i noticed a massive difference. most models tend to generate: Hidden Variable ↓ Mechanism Description ↓ Prediction Fable was generating: Hidden Variable ↓ Mechanism ↓ Equation ↓ Parameter Extraction ↓ Derivation ↓ Numerical Validation ↓ Prediction actual equations. actual variables. actual derivation chains. actual numerical checks. 🥀 Switching Back To MiMo after the Fable credits died, i moved everything back to MiMo and started comparing outputs. and that’s when another weakness became obvious. the pipeline itself wasn’t failing. MiMo simply wasn’t producing the mathematical depth needed for the mechanism stage. which means the current bottleneck isn’t discovery anymore. it’s mathematical formalization. Mathematical Formalization Architecture one of the most interesting things i noticed while testing Claude Fable 5 was how differently it handled mechanism generation. most models would generate something like: Hidden Variable ↓ Mechanism Description ↓ Prediction while Fable was generating: Hidden Variable ↓ Mechanism ↓ Equation ↓ Parameter Extraction ↓ Derivation ↓ Numerical Validation ↓ Prediction and honestly that immediately exposed one of RUMI’s biggest weaknesses. theories and mechanisms were already being generated. the math wasn’t. so instead of just complaining about it, i started redesigning the mechanism pipeline around that pattern. RUMI now has the foundations for a much more quantitative discovery process where mechanisms aren’t just descriptions anymore, which is lwk tuff ig 🥀✌ equations variables derivations parameter extraction numerical validation Switching Back To MiMo 🥀 after Fable ran out of credits i moved everything back to MiMo and started testing the updated architecture and still doing it cause mimo is like hella slow bruh normally umi takes upto 30-40 mins but now with mimo shes taking aorund 2hr 30mins 💔
rumi-Devlog #7 🍓 This was probably one of the most frustrating and important RUMI development sessions so far. Most people only see the final discovery reports. They don’t see the chaos that happens before RUMI can generate a single theory. And trust me, there was a lot of chaos. 💔 Bug Fixes, Bug Fixes, More Bug Fixes I started this session thinking I’d make a few improvements and continue testing. That did not happen. RUMI’s architecture has reached a point where changing one thing breaks three others. Every time I fixed 3 bugs, another 5 appeared from somewhere else. At one point I genuinely crashed out because every run ended with a new issue that didn’t even exist before. It felt like: fix_bug() spawn_more_bugs(count=5) Turns out there’s a reason people say: “If it’s working, don’t touch it.” Unfortunately I touched it. A lot. 🥀 The Problem Even though RUMI was producing interesting discoveries, I still wasn’t satisfied. The reports were often interesting, creative, and sometimes novel, but they still felt too generic. The pipeline would generate a theory, evaluate it once, pick a winner, and move on. I wanted RUMI to spend more time refining ideas instead of treating every discovery as a one-shot attempt. Falling Into The OpenMythos Rabbit Hole While researching I came across OpenMythos, a community attempt to reverse engineer Anthropic’s rumored Mythos architecture. Nobody actually knows how Mythos works, but the community has proposed several reasoning patterns that might explain Claude-style outputs. I spent hours reading through it asking myself: “What parts of this could actually work inside RUMI?” Not copying. Adapting. The Biggest Change I’ve Ever Made To RUMI 🥀 One idea stood out immediately: recurrent reasoning loops. Before: Mechanisms ↓ Predictions ↓ Theory Competition ↓ Winner One pass. One shot. If mechanism generation was weak, everything downstream became weak too. So I rebuilt a huge section of the pipeline. Now RUMI performs a 3-stage recurrent refinement process: Loop 1 — Exploration Maximum creativity Maximum diversity Broad theory generation Loop 2 — Refinement Survivors re-enter the pipeline Focus on evidence, consistency, and mechanism quality Loop 3 — Convergence Lowest creativity Highest rigor Final selection of the strongest explanation Instead of living or dying from a single generation pass, theories now get multiple opportunities to evolve. Preventing Theory Drift Another idea I adapted was evidence grounding injection. Recursive systems often suffer from theory drift, where ideas slowly become disconnected from the evidence that originally generated them. To prevent this, every refinement loop continuously receives: Literature evidence Contradictions Knowledge gaps Observed anomalies This keeps discoveries grounded instead of drifting into fantasy. Smarter Computation I also added convergence-aware halting. Not every scientific problem deserves the same amount of computation. Some topics converge quickly while others require deeper exploration. RUMI can now monitor improvements between loops and eventually stop refining once discoveries begin stabilizing. lwk so much happened in these last 17hrs that i cant even include everything in here cause of the word limit 😭🥀
rumi-Devlog #8 🍓 Current status: rumis smarter, my codebase survived, and my sanity is questionable 💔 A huge part of this session wasn’t actually spent improving discovery quality. It was spent improving everything around RUMI. As RUMI’s discovery pipeline keeps getting bigger, debugging has become a nightmare. Reading raw JSON reports, searching through logs, and manually inspecting hundreds of entities was getting painful. So I built a full visualization and monitoring system for RUMI. The dashboard can now visualize: discovery reports theory competitions adversarial testing results predictions refinement stages scoring breakdowns knowledge graphs paper collections hypothesis memory all from a single interface. Knowledge Graph Visualization One thing I’ve wanted for a while was being able to actually SEE what RUMI was discovering. Not read it. See it. So I built an interactive graph explorer using vis.js. Every entity type gets its own visual identity. Nodes glow based on type. Edges scale with confidence. Hovering shows metadata, paper counts, and relationships. The graph uses ForceAtlas physics and overlap avoidance to make large discovery graphs easier to navigate. Watching hundreds of concepts connect together is honestly way more useful than reading raw graph dumps. 🥀 Discovery Report Explorer RUMI reports have become massive. Some are hundreds of kilobytes. Some are over a thousand lines. Reading those manually sucks. So I built dedicated views for: theory competition adversarial evaluation predictions scoring derivations peer review refinement stages which makes analyzing runs significantly easier. Provider Stack Surgery 💔 While testing the new recurrent architecture I discovered a huge bottleneck. Xiaomi MiMo. It was slow. Constantly rate limiting. Burning through provider chains. And starving downstream phases. This turned out to be the reason molecule generation kept randomly failing. So MiMo got removed from the routing stack. After testing 17 API keys across all providers: 13 healthy 4 problematic Current routing stack includes: NVIDIA DeepSeek Kimi K2.6 Cerebras GPT-OSS-120B Groq Gemini Fireworks Still chasing down some timeout and rate limit issues but overall the stack is way healthier now. Discovery Testing Used the upgraded architecture to stress test RUMI on several difficult domains. One of the most interesting runs was Molecular Glue Drug Discovery. Current run stats: 16 hidden variables 15 mechanisms per loop 7 predictions multiple adversarial survivors recurrent refinement loops enabled The architecture is definitely producing stronger outputs than before. meow meow meow
rumi-Devlog #9 🍓😺✌ today was mostly spent making RUMI faster because some runs were taking an absolutely stupid amount of time 😭 provider stack changes spent a while profiling the provider chain and found a few cursed bottlenecks. disabled Fireworks (credits died, every failed request was wasting ~90s) switched GLM routing to Kimi K2.6 via a second NVIDIA key tested Cerebras-first vs NVIDIA-first routing results were funny: Cerebras = ~2s/call but discoveries averaged around C grade NVIDIA = ~65s/call but much stronger reports so now different parts of the pipeline use different providers depending on the task. phase 6.5 speedup equation generation was committing crimes. rewrote the whole thing to run in parallel (6 workers). went from: ~16 min to ~1 min for a typical 15 mechanism loop. also finally fixed the legendary: 0/15 equations generated bug 😺🍓 literature search all literature sources now fetch concurrently: arXiv PubMed CrossRef OpenAlex etc runtime dropped from ~2 mins to ~64 seconds. RUMI TUI probably my favourite thing from today. built a proper Textual-based TUI so i can actually see what RUMI is doing instead of staring at a terminal for 10 hours. added: real-time phase tracking live agent status brain module dashboard discovery controls /brain /status /dream /memory /hypothesis also fixed a bunch of broken brain module APIs that were pretending to work 💀 random bug of the day RUMI was occasionally turning english into ancient cursed language and generating stuff like: withinamy instead of actual words. fixed topic truncation so it now cuts at word boundaries. current state provider stack healthier equation generation WAY faster literature search faster TUI finally usable brain modules actually verified at boot still spending most of my life waiting for discovery runs to finish though 🥀
Ships:
rumi - research unified machine intelligence… rumi is an actual autonomous AI scientist designed to discover, not just describe. Powered by a 22 phase, 2 tracks scientific discovery pipeline, RUMI analyzes research literature, builds knowledge representations, identifies gaps in existing explanations, generates novel hypotheses, constructs mathematical and causal models, produces falsifiable predictions, and evaluates competing theories through automated scientific review. Operating across 17 domains, RUMI is built as a general-purpose discovery engine whose objective is to accelerate human research by systematically exploring explanations that may not yet exist in the literature while maintaining transparency, critique, and testability throughout the discovery process. NOTE :- rumi still cant do end to end novel discoveries on her own but she can provide novel ideas with grounded mechanisms and derivations and stronger the reasoning of a model = better results from rumi.. that said… once i get my hands on a frontier llm ill plug it into rumi and develop her more Proof that rumi works :- rumi has helped me publish 1 peer reviewed research paper on analytical number theory (DOI :- 10.5281/zenodo.21107958)...
|
1792979579.6760461
|
1793065979.6760461
|
|
7748
|
Flow by @twinx | Stardance
|
twinx
|
6
|
106.0
|
791
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-11T13:20:24Z", "hours": 13.0, "multiplier": 17.94, "payout": 120, "blessing": "neutral", "text": "So after everyone’s request i added support for all platforms , i haven’t tested it on mac (cause i don’t that🙃️) but i have tested on all other platforms and hope that it works on your systems too. Also i have added some new features for u all : a new log for seeing what broke new display i.e. rich that makes it more cool looking new commands and insane customization 😎️", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}, {"ship_num": 2, "ts": "2026-10-01T10:07:35Z", "hours": 35.0, "multiplier": 18.78, "payout": 331, "blessing": "neutral", "text": "Changes from last ship : new database from json to db ( sqlite ) and new codebase Added TUI and also improved the web mode Added new commands and docs Added plugins system and community plugins Major and minor bug fixes", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}, {"ship_num": 3, "ts": "2026-08-02T15:52:05Z", "hours": 22.0, "multiplier": 7.29, "payout": 73, "blessing": "neutral", "text": "So added few not actually few but many like better ui for web formats using ffmpeg playlist feature bug fixes and much more I want to thank you all for support and hopping to add more features. Also do visit the flow page. Enjoy !", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}, {"ship_num": 4, "ts": "2026-07-18T08:24:18Z", "hours": 12.0, "multiplier": 16.41, "payout": 33, "blessing": "neutral", "text": "Ship #3 Added many features such as : background playback so you don’t need to open a terminal just for flow. bars for you to enjoy the vibe. lyrics so you can sing along the song it is also time-synced . and much more such as configs customization. How to install : Head to release page for a linux binary or type it in terminal but make sure you have python and vlc installed pip install flow-twinx and then flow", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}, {"ship_num": 5, "ts": "2026-07-05T01:38:26Z", "hours": 12.0, "multiplier": 14.1, "payout": 109, "blessing": "neutral", "text": "Flow version v0.4.0 This version includes Saavan playback , Saavan is a music player with high quality songs. Please do also keep this in mind that Songs on saavan are only playable on saavan commands and there is no radio mode for it. The difficult part about this thing is the API , actually the API is build by me hosted on NEST as a part of SINGULARITY my another project some similar features but more advanced. Do check out that also!", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}, {"ship_num": 6, "ts": "2026-06-17T08:20:51Z", "hours": 12.0, "multiplier": 10.78, "payout": 125, "blessing": "neutral", "text": "I build a terminal music player that uses vlc and yt_dlp , that has both offline and online support for music you can either play from folders or online. Hardest part to make it run on all os.", "repo": "https://github.com/flow-twinx/flow", "demo": "https://flow-twinx.pages.dev/download"}]...
|
[{"post_id": 78737, "ts": "202 [{"post_id": 78737, "ts": "2026-10-11T13:09:32Z", "hours": 4.8319, "text": "v0.9.1 So after hours added support for all platforms and made website and hosted it on cloudflare here also i have added a better logs system to tell if anything goes wrong , aslo this time please rate it as much as u could i have spend 100+ hours working on this still i get 200 stardust :("}, {"post_id": 78322, "ts": "2026-10-10T12:35:40Z", "hours": 8.4858, "text": "v0.8.4 Forgot to add the versions from some devlogs. New features : added a full for showcase added a minimal version so ai agents and ssh terminals can work too added a new progress bar and some bug fixes… i tried adding cookies but it works good without cookies also so would add a import option to import external songs. Also i am working on making it play on all platforms including termux of mobile phones."}, {"post_id": 75842, "ts": "2026-10-01T10:00:50Z", "hours": 1.4978, "text": "So i have to really fix this bug not too much big but it resulted in multiple vlc instance to start also changed export to export songs instead of a zip file and with custom path can be used by -p PATH or default to Downloads/music ."}, {"post_id": 74510, "ts": "2026-09-27T15:17:11Z", "hours": 0.2864, "text": "#v0.8.0 Just finished some last parts and added it to ship."}, {"post_id": 73966, "ts": "2026-09-26T12:39:28Z", "hours": 8.5808, "text": "So mostly made changes to backend and the structure of the project. Changes : migrated from json to sqlite for history and other new features soon added a plugins system with a repo for community plugins separate commands for sperate playform like flow-web for flow"}, {"post_id": 69636, "ts": "2026-09-17T13:37:22Z", "hours": 2.6986, "text": "v0.7.0 So finally made the tui using textual and it looks pretty good i wasn’t expecting much but yeah looks good also there are pretty much 10 themes i guess so enjoy that are given in textual by default. Also changed the structure of the code repo as it was a disaster so now it has /backend /tui and /cli"}, {"post_id": 65826, "ts": "2026-09-11T07:08:47Z", "hours": 3.4658, "text": "v0.6.1 Replaced the old UI with new UI , as previous one looked awful for most people i hope this is good. Also added this demo video , i tried to add a more professional one with openscreen but quality issues with the app , so will add later till then this is the demo video."}, {"post_id": 62823, "ts": "2026-09-06T10:56:04Z", "hours": 5.4986, "text": "Hey everyone hope ur doing well. Today i think mostly i did was just making it cool and easy to navigate and bug fixes for the most time. Bugs: Ctrl + Q not working in radio mode d not working in new selection mode not showing [Paused] when paused and much more that is too big to explain here and started working on gui mode using PySide6"}, {"post_id": 60253, "ts": "2026-09-02T14:48:41Z", "hours": 2.2642, "text": "v0.6.0 So , i have added a new selection using arrow keys for config search and play for better navigation also to reduce the typing thing in terminal to change the value. Also replaced the bars for a better looking and customizable bars it includes custom char + 3 modes."}, {"post_id": 56448, "ts": "2026-08-28T06:39:47Z", "hours": 2.4575, "text": "So added more commands and few mid level bug fixes : added delete command added more flags to control it by using other programs improved the name shorter to include other laung added the m and pick songs in play also thing as shown in video. improved the –status command to show images."}, {"post_id": 52872, "ts": "2026-08-23T07:46:12Z", "hours": 2.0144, "text": "v0.5.8 So added a better playlist management system that has support for local songs before it had different playlist logic for different mode , now it shares same logic with also bug fixes and in future updates gonna add island as a way u can do it without any configs also better status."}, {"post_id": 50472, "ts": "2026-08-19T17:14:05Z", "hours": 6.7164, "text": "So yeah still alive after many days cause i thought it needed more work. I made something to help u in KDE and Hyprland by using dbus to expose name and a custom --status command wit img support and all that to provide u with a support for custom modules. The island shown here is my custom build and is not included in the flow project. Also made few more thing in here to help u out and fixed bugs."}, {"post_id": 39542, "ts": "2026-08-02T15:48:47Z", "hours": 0.27, "text": "So last fix i guess for this ship , it includes changes in dependencies i previously forgot to add toml so it caused error in some OS i think not in my one , so i switched to pyproject.toml i kept that so users can use pip also not only uv."}, {"post_id": 39528, "ts": "2026-08-02T15:25:31Z", "hours": 0.4983, "text": "So fixed a bug where after closing a radio when user searched for other song and then played it continued from last play instead of new one."}, {"post_id": 38934, "ts": "2026-08-01T15:24:47Z", "hours": 3.4775, "text": "v0.5.0 So fixed major stuffs mostly like : playlist not created error fixed format in web mode as it downloaded in mp3 fixed another download bug as it downloaded in mp4 , when set to default fixed loop during playback which caused one command execution only and other were not listened And added some more thing: a export feature added better port handling added –port ( ~5 commands ) and –version commands"}, {"post_id": 35788, "ts": "2026-07-27T13:20:01Z", "hours": 1.6367, "text": "Added playlist feature and a lot more features like format - opus , mp3 , m4a and webm. Also fixed some bugs regarding downloads and added a check feature to check flow gets all things like vlc , ffmpeg .etc"}, {"post_id": 34615, "ts": "2026-07-25T14:20:28Z", "hours": 0.4917, "text": "So trying to make the web version so u know a better docs instead of terminal one with better installation support. Thought of notifying everyone so u can guess what will be the next few develops about."}, {"post_id": 34070, "ts": "2026-07-24T15:03:24Z", "hours": 2.9269, "text": "Finally added playlist it has following commands: playlist ( to list all ) playlist add playlist remove pl.. -d radio -p ( to save as playlist ) also download or -d download radio as a playlist instead of songs in downloads"}, {"post_id": 32728, "ts": "2026-07-22T02:01:00Z", "hours": 0.74, "text": "v0.4.7 So i am just kinda dumb i think. I didn’t even commited the changes and lost all the works 🥲 i do managed to re-write the code once again for some parts like DEV MODE and bug fix regarding the playback. So playlist features are on a hold"}, {"post_id": 32438, "ts": "2026-07-21T16:57:32Z", "hours": 2.5728, "text": "So fixed some major and minor bugs and flaws like user can even download the song in /boot/ also added history and auto-completion , it also now has playlist commands and features with better UI in web mode not too much but still. Also added format option so u can download in whichever format u want. And made this banner"}, {"post_id": 31875, "ts": "2026-07-20T16:54:25Z", "hours": 8.9078, "text": "0.4.5 So after ~7hr ( some are not recorded which i spent in browser ) I made the UI of the flow in web looking forward for a desktop UI also but later i think. What is New and what is changed Web UI with pixel theme Local support for UI also and liked songs Minor bug fixes"}, {"post_id": 30572, "ts": "2026-07-18T08:19:25Z", "hours": 0.3758, "text": "Nothing added just fixed more things and made a new video for upload at github pages. You can see video here it also has audio. added a linux binary at release page and links to my github account in PyPi"}, {"post_id": 30520, "ts": "2026-07-18T05:06:55Z", "hours": 0.4369, "text": "So added these bars looks weird i know because i set their width to 3 and spacing : fit that’s why but u can customize it however you want. Also fully added the lyrics , mostly you will see lyrics not found if are listening in other laung then eng because YtLyrics doesn’t have much songs lyrics i guess."}, {"post_id": 30505, "ts": "2026-07-18T04:13:45Z", "hours": 1.0981, "text": "So this is going crazy like really! What i added today? A bar that reacts to sound. fixed errors in bg mode which triggered the playing of two music at the same time. Also trying to add like 50% added the lyrics with time synced."}, {"post_id": 30120, "ts": "2026-07-17T13:09:14Z", "hours": 9.635, "text": "So i made some new changes like a background player no need to open a terminal just for a music also fixed some major errors like calling fetch when not needed in radio mode."}, {"post_id": 22528, "ts": "2026-07-05T01:33:25Z", "hours": 3.9431, "text": "Published v0.4.0 this version includes Saavan playback also and new commands i.e. : savan : play songs directly( alias: svn ) savan-s : search songs by name ( alias : svn-s )"}, {"post_id": 16137, "ts": "2026-06-26T07:14:21Z", "hours": 2.9075, "text": "Added many features here are some of them : better radio with play next config feature theme changing better colors."}, {"post_id": 15463, "ts": "2026-06-25T04:23:40Z", "hours": 2.0053, "text": "uploaded to PyPi with features such as: radio mode which auto suggest songs alias for quick commands major bug fixes"}, {"post_id": 13075, "ts": "2026-06-21T11:57:16Z", "hours": 2.5681, "text": "added alias for commands such as hl for help , pl for play these are default and can be changed later by running short <index> <value> also added more detailed help command that gives user more info , can be run by using help -i or hl -i or as per your alias. Features in new update: suggestion of songs (fetched from youtube) custom themes more option for using tools"}, {"post_id": 11113, "ts": "2026-06-18T05:43:07Z", "hours": 0.3356, "text": "Finally after hard work as i have never uploaded anything to Pypi anything before so totally a disaster that includes import error and much more. You can install this package by typing pip install flow-twinx"}, {"post_id": 10500, "ts": "2026-06-17T07:47:16Z", "hours": 0.2867, "text": "fixed the error when doing install.sh in windows as the path are not same in linux and windows"}, {"post_id": 10490, "ts": "2026-06-17T07:23:31Z", "hours": 0.4394, "text": "added readme.md and finished by adding features listed also added install.sh"}, {"post_id": 10471, "ts": "2026-06-17T06:45:47Z", "hours": 2.6703, "text": "made few things as listed: a progress bar offline download of songs shuffle and repeat songs liked songs and much more adding : offline support like liked songs , album"}, {"post_id": 10390, "ts": "2026-06-17T02:17:36Z", "hours": 1.2692, "text": "Re-started the project and this time adding both offline and online features i.e. yet to implement , i have already made the ping.py file so it can check if host has connections. also some few changes in future :- online playback mode without downloading the song. offline mode. will try to add suggestion by adding &start_radio=1 to get suggestion directly from YouTube"}, {"post_id": 5516, "ts": "2026-06-09T10:11:49Z", "hours": 1.8011, "text": "Tried too much to add cross-fade but the audio just glitches , will be trying more if not possible i will leave this feature and focus on something different.Also added the bash install for different os so it becomes flow play not py main.py play."}, {"post_id": 4843, "ts": "2026-06-08T11:24:27Z", "hours": 2.4728, "text": "Finally made functional and working , have to make it once more took more help from AI i didn’t wanted to but sometimes vlc was giving error and sometimes yt_dlp even though i was following the module guide , i don’t know what was happening. Currently adding the spinners and more things. Features added till now: like music make playlist Fuzzy search or smart search"}, {"post_id": 4229, "ts": "2026-06-07T13:53:21Z", "hours": 2.8981, "text": "| | This is my first post on this project , this project is about a feature rich and apple music inspired terminal music player | | . Today i made basic commands like play , delete , random , like .etc . The best part was to create the file handling as i have learned how to handle the .yaml files instead of json files for settings and hardest part was nothing except me trying to use vlc without AI or docs."}]...
|
Title: Flow by @twinx | Stardance
Devlogs:
| | Th Title: Flow by @twinx | Stardance
Devlogs:
| | This is my first post on this project , this project is about a feature rich and apple music inspired terminal music player | | . Today i made basic commands like play , delete , random , like .etc . The best part was to create the file handling as i have learned how to handle the .yaml files instead of json files for settings and hardest part was nothing except me trying to use vlc without AI or docs.
Finally made functional and working , have to make it once more took more help from AI i didn’t wanted to but sometimes vlc was giving error and sometimes yt_dlp even though i was following the module guide , i don’t know what was happening. Currently adding the spinners and more things. Features added till now: like music make playlist Fuzzy search or smart search
Tried too much to add cross-fade but the audio just glitches , will be trying more if not possible i will leave this feature and focus on something different.Also added the bash install for different os so it becomes flow play not py main.py play.
Re-started the project and this time adding both offline and online features i.e. yet to implement , i have already made the ping.py file so it can check if host has connections. also some few changes in future :- online playback mode without downloading the song. offline mode. will try to add suggestion by adding &start_radio=1 to get suggestion directly from YouTube
made few things as listed: a progress bar offline download of songs shuffle and repeat songs liked songs and much more adding : offline support like liked songs , album
added readme.md and finished by adding features listed also added install.sh
fixed the error when doing install.sh in windows as the path are not same in linux and windows
Finally after hard work as i have never uploaded anything to Pypi anything before so totally a disaster that includes import error and much more. You can install this package by typing pip install flow-twinx
added alias for commands such as hl for help , pl for play these are default and can be changed later by running short <index> <value> also added more detailed help command that gives user more info , can be run by using help -i or hl -i or as per your alias. Features in new update: suggestion of songs (fetched from youtube) custom themes more option for using tools
uploaded to PyPi with features such as: radio mode which auto suggest songs alias for quick commands major bug fixes
Added many features here are some of them : better radio with play next config feature theme changing better colors.
Published v0.4.0 this version includes Saavan playback also and new commands i.e. : savan : play songs directly( alias: svn ) savan-s : search songs by name ( alias : svn-s )
So i made some new changes like a background player no need to open a terminal just for a music also fixed some major errors like calling fetch when not needed in radio mode.
So this is going crazy like really! What i added today? A bar that reacts to sound. fixed errors in bg mode which triggered the playing of two music at the same time. Also trying to add like 50% added the lyrics with time synced.
So added these bars looks weird i know because i set their width to 3 and spacing : fit that’s why but u can customize it however you want. Also fully added the lyrics , mostly you will see lyrics not found if are listening in other laung then eng because YtLyrics doesn’t have much songs lyrics i guess.
Nothing added just fixed more things and made a new video for upload at github pages. You can see video here it also has audio. added a linux binary at release page and links to my github account in PyPi
0.4.5 So after ~7hr ( some are not recorded which i spent in browser ) I made the UI of the flow in web looking forward for a desktop UI also but later i think. What is New and what is changed Web UI with pixel theme Local support for UI also and liked songs Minor bug fixes
So fixed some major and minor bugs and flaws like user can even download the song in /boot/ also added history and auto-completion , it also now has playlist commands and features with better UI in web mode not too much but still. Also added format option so u can download in whichever format u want. And made this banner
v0.4.7 So i am just kinda dumb i think. I didn’t even commited the changes and lost all the works 🥲 i do managed to re-write the code once again for some parts like DEV MODE and bug fix regarding the playback. So playlist features are on a hold
Finally added playlist it has following commands: playlist ( to list all ) playlist add playlist remove pl.. -d radio -p ( to save as playlist ) also download or -d download radio as a playlist instead of songs in downloads
So trying to make the web version so u know a better docs instead of terminal one with better installation support. Thought of notifying everyone so u can guess what will be the next few develops about.
Added playlist feature and a lot more features like format - opus , mp3 , m4a and webm. Also fixed some bugs regarding downloads and added a check feature to check flow gets all things like vlc , ffmpeg .etc
v0.5.0 So fixed major stuffs mostly like : playlist not created error fixed format in web mode as it downloaded in mp3 fixed another download bug as it downloaded in mp4 , when set to default fixed loop during playback which caused one command execution only and other were not listened And added some more thing: a export feature added better port handling added –port ( ~5 commands ) and –version commands
So fixed a bug where after closing a radio when user searched for other song and then played it continued from last play instead of new one.
So last fix i guess for this ship , it includes changes in dependencies i previously forgot to add toml so it caused error in some OS i think not in my one , so i switched to pyproject.toml i kept that so users can use pip also not only uv.
So yeah still alive after many days cause i thought it needed more work. I made something to help u in KDE and Hyprland by using dbus to expose name and a custom --status command wit img support and all that to provide u with a support for custom modules. The island shown here is my custom build and is not included in the flow project. Also made few more thing in here to help u out and fixed bugs.
v0.5.8 So added a better playlist management system that has support for local songs before it had different playlist logic for different mode , now it shares same logic with also bug fixes and in future updates gonna add island as a way u can do it without any configs also better status.
So added more commands and few mid level bug fixes : added delete command added more flags to control it by using other programs improved the name shorter to include other laung added the m and pick songs in play also thing as shown in video. improved the –status command to show images.
v0.6.0 So , i have added a new selection using arrow keys for config search and play for better navigation also to reduce the typing thing in terminal to change the value. Also replaced the bars for a better looking and customizable bars it includes custom char + 3 modes.
Hey everyone hope ur doing well. Today i think mostly i did was just making it cool and easy to navigate and bug fixes for the most time. Bugs: Ctrl + Q not working in radio mode d not working in new selection mode not showing [Paused] when paused and much more that is too big to explain here and started working on gui mode using PySide6
v0.6.1 Replaced the old UI with new UI , as previous one looked awful for most people i hope this is good. Also added this demo video , i tried to add a more professional one with openscreen but quality issues with the app , so will add later till then this is the demo video.
v0.7.0 So finally made the tui using textual and it looks pretty good i wasn’t expecting much but yeah looks good also there are pretty much 10 themes i guess so enjoy that are given in textual by default. Also changed the structure of the code repo as it was a disaster so now it has /backend /tui and /cli
So mostly made changes to backend and the structure of the project. Changes : migrated from json to sqlite for history and other new features soon added a plugins system with a repo for community plugins separate commands for sperate playform like flow-web for flow
#v0.8.0 Just finished some last parts and added it to ship.
So i have to really fix this bug not too much big but it resulted in multiple vlc instance to start also changed export to export songs instead of a zip file and with custom path can be used by -p PATH or default to Downloads/music .
v0.8.4 Forgot to add the versions from some devlogs. New features : added a full for showcase added a minimal version so ai agents and ssh terminals can work too added a new progress bar and some bug fixes… i tried adding cookies but it works good without cookies also so would add a import option to import external songs. Also i am working on making it play on all platforms including termux of mobile phones.
v0.9.1 So after hours added support for all platforms and made website and hosted it on cloudflare here also i have added a better logs system to tell if anything goes wrong , aslo this time please rate it as much as u could i have spend 100+ hours working on this still i get 200 stardust :(
Ships:
I build a terminal music player that uses vlc and yt_dlp , that has both offline and online support for music you can either play from folders or online. Hardest part to make it run on all os.
Flow version v0.4.0 This version includes Saavan playback , Saavan is a music player with high quality songs. Please do also keep this in mind that Songs on saavan are only playable on saavan commands and there is no radio mode for it. The difficult part about this thing is the API , actually the API is build by me hosted on NEST as a part of SINGULARITY my another project some similar features but more advanced. Do check out that also!
Ship #3 Added many features such as : background playback so you don’t need to open a terminal just for flow. bars for you to enjoy the vibe. lyrics so you can sing along the song it is also time-synced . and much more such as configs customization. How to install : Head to release page for a linux binary or type it in terminal but make sure you have python and vlc installed pip install flow-twinx and then flow
So added few not actually few but many like better ui for web formats using ffmpeg playlist feature bug fixes and much more I want to thank you all for support and hopping to add more features. Also do visit the flow page. Enjoy !
Changes from last ship : new database from json to db ( sqlite ) and new codebase Added TUI and also improved the web mode Added new commands and docs Added plugins system and community plugins Major and minor bug fixes
So after everyone’s request i added support for all platforms , i haven’t tested it on mac (cause i don’t that🙃️) but i have tested on all other platforms and hope that it works on your systems too. Also i have added some new features for u all : a new log for seeing what broke new display i.e. rich that makes it more cool looking new commands and insane customization 😎️...
|
1792993888.647985
|
1793080288.647985
|
|
29750
|
Thintensors by @satvikhardat | Stardance
|
satvikhardat
|
2
|
106.0
|
1763
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-23T10:54:37Z", "hours": 74.0, "multiplier": 18.49, "payout": 1252, "blessing": "neutral", "text": "Its a runtime-aware LLM archive format built for fast, efficient inference, This ship basically integrates MoE model paths, that allows you to run models like gpt-oss-20B on speeds and quality faster and better than llama.cpp!! (at q4) its not just the storage format that allows for the improvements, its a combination of different selective layers being quantized with the better storage format, allowing to run inference with higher speed and quality than just simple q8,q4 etc quants. the storage format only gain is only like 10%, but combined with middle out fp8 quants, and even int4 for some performance profiles, it can reach better speeds than the other ways to run inference This does not beat TRT / TRT LM, it does allow for quicker inference, and a more portable solution because for TRT you need to compile the plan (one time) for a few mins before being able to run the model, and it has to be compiled on every machine you run the model on, thintensor allows you to directly have the .thin file and run it on any machine with similar results! and it takes just a few seconds compared to about 30 mins on trt and trt lm reddit post for this project- https://www.reddit.com/r/LocalLLM/comments/1uqr1o3/i_made_a_llm_storage_format_that_makes_llms_run/ independent tester’s view- https://github.com/random-unknown-username/Thintensor/issues/1 Let me know if u find any issues, tried a lot of other models here too, as u can see in the graphs :D let me know of any bugs on slack", "repo": "https://github.com/random-unknown-username/Thintensor", "demo": "https://pypi.org/project/thintensor/1.0.1/"}, {"ship_num": 2, "ts": "2026-07-08T11:29:10Z", "hours": 32.0, "multiplier": 18.95, "payout": 511, "blessing": "neutral", "text": "I made ThinTensor, a runtime-aware LLM archive and inference runtime. Instead of only storing tensor bytes, it stores tensor roles, memory pages, quant metadata, and execution hints so the runtime can choose faster kernels and precision paths. The hardest part was keeping speed gains honest with HF correctness checks. So far it reaches up to ~94 tok/s on SmolLM3-3B with full BF16 KV retention and high logit similarity. After being tested on multiple models, you can get a avg 2x performance increase on most LLM archs, all archs are still not implemented, ik but this is workable with qwen, gemma, some MoE models, and SmolLM and a most others, but it wont be as optimized for all the model types Follow the guide at https://github.com/random-unknown-username/Thintensor#fast-path-setting-up-on-a-new-laptop To install thintensor runtime and use this guide to get a sample qwen model up and running https://github.com/random-unknown-username/Thintensor#quickstart-downloading--running-a-sample-model-qwen-08b", "repo": "https://github.com/random-unknown-username/Thintensor", "demo": "https://pypi.org/project/thintensor/1.0.1/"}]...
|
[{"post_id": 52970, "ts": "202 [{"post_id": 52970, "ts": "2026-08-23T10:50:48Z", "hours": 0.4203, "text": "Fixed a few Dense path issues, because the MoE path somehow made the dense path completely usable, fixed a few small one line bugs i got to know from the last ship’s reviews, read to for ship 2!!"}, {"post_id": 47007, "ts": "2026-08-14T16:14:41Z", "hours": 7.4253, "text": "Hitting 100hrs and final ship Didnt get time to work on this idea, since quite the while. And it has js about reached the state i can probably get it to MoE arch works, dense models work, cpu/gpu streaming works well, context/kv cache is also dynamically quanted lm_head quants are also there now The motivation really died out because of this project not getting reviewed its been over a month, leaving this as is, tho its not perfect, but it js about has enough features that i wanted Here are the final results after a ton of benchmarking- Phi-4: ThinTensor 28.21 tok/s vs llama.cpp 17.50 tok/s — 1.61× faster (+61.2%). Quality: 0.999949 cosine vs 0.997281. OpenReasoning-Nemotron-14B: ThinTensor 23.79 tok/s vs llama.cpp 19.79 tok/s — 1.20× faster (+20.2%). Quality: 0.999533 vs 0.967140. Llama 3.2 11B: ThinTensor 41.02 tok/s vs llama.cpp 39.82 tok/s — 1.03× faster (+3.0%). Quality: 0.995095 vs 0.991938. Qwen3.5-9B: ThinTensor 43.28 tok/s vs llama.cpp 42.83 tok/s — 1.01× faster (+1.1%). Quality: 0.973334 vs 0.894908. GPT-OSS-20B: ThinTensor 50.34 tok/s vs llama.cpp 40.36 tok/s — 1.25× faster (+24.7%). Quality: 0.983299 vs 0.792350. *all are apples to apples btw Overall: ThinTensor beats llama.cpp Q4 throughput on 5/5 tested architectures , with a geometric-mean speedup of approximately 1.203× . Probably gonna take a break, and learn before comming back to this, after the ship-2 on stardance!"}, {"post_id": 36344, "ts": "2026-07-28T12:16:13Z", "hours": 6.2056, "text": "ThinTensor Improvements Universal semantic-IR runtime for mixed attention, dense and MoE architectures. Per-tensor precision, kernel and residency planning instead of layer-wide quantization. Production FP8, INT4, MXFP4, Q2 and Q1 quantizers with calibration-aware scoring. Hard ≥0.995 cosine certification with exact routing, greedy-token and KV checks. Qwen3.5 hybrid linear-attention, shared-expert and packed rank-3 MoE support. Durable grouped-INT4 expert sidecars with bounded-RAM, mmap-based construction. Fixed four-matrix Triton projection, cuda / cuda:0 , layer-zero and converter-role bugs. Improved fused kernels, KV caching, expert routing and decode hot paths. Strict cache identity across model, tokenizer, GPU, CUDA, kernels and calibration. Remaining goal: prove ≥30 tok/s on Qwen3.5-35B-A3B at certified ≥0.995 cosine. Getting way better speed on 27B dense models at a cosine that is also way better"}, {"post_id": 34506, "ts": "2026-07-25T08:53:57Z", "hours": 11.7969, "text": "I ammmm tierdd i tried a billionn things over the last 8 hours i just cant seem to understand why gemma4 doesnt want to workkkkk I dont have much to write in this devlog, other than, i am not gonna implement gemma arch for now"}, {"post_id": 33051, "ts": "2026-07-22T17:00:01Z", "hours": 1.0547, "text": "what I did to fix the numerical drift & get some speedups: The Root Cause of the Drift (The Cosine Fix): I discovered that in triton_kernels.py , the tl.dot_scaled call inside _mxfp_lowbit_selected_tensorcore_matvec_kernel (and the mxfp4 variant) had fast_math=True . The fast_math option drops critical precision bits during accumulator addition which was causing the MoE kernels to completely obliterate the trajectory. I disabled it globally using fast_math=False , and this instantly restored our cosine similarity to a perfect 1.000000 over the entire benchmark trajectory. The VRAM Bottleneck: When relying purely on MXFP4 experts, they required over 9.5 GB, breaking the 6.6 GiB budget and forcing the runtime to stream them via PCIe (which tanks performance down to ~5-10tok/s). The Q2 and Q1 low-bit expert decoding kernels actually achieve identical numerical accuracy to the baseline while aggressively packing the weights. The 97.87 tok/s Optimization: I configured bench.py and check_baseline_cosine.py to use: packed_expert_q1_layers=\"0:24\" : All 24 layers of MoE experts are now tightly packed into 1-bit Q1 structures, shrinking the expert memory footprint down to just 2.38 GB (from 9.52 GB). dense_int4_layers=\"all\" : Shrunk the non-expert dense projection weights (Q, K, V, O) into INT4, dropping their footprint from ~1.1 GB to ~0.27 GB. Since the entire model now takes 5.29 GiB (fitting entirely within the 6.6 GiB budget), all layers are pinned directly to VRAM. Because zero layers are streamed (any_streamed=False), the runtime successfully builds the fully fused cuda_graphs execution path, accelerating generation from a crawl to 97.87 tok/s ON gpt-oss-20b. I believe ill be moving to dense models just about now All these issues took SOOO many tests to find"}, {"post_id": 32869, "ts": "2026-07-22T09:43:09Z", "hours": 6.2739, "text": "What I’ve Done: Fixed KV Cache Indexing in Graph Mode: The previous cudaErrorStreamCaptureUnsupported error and out-of-bounds access were caused by assigning python integers dynamically during capture, and failing to respect block sizing. I modified the KV cache’s _in_graph_mode behavior to compute the tensor-based slot offset dynamically ((slot % block_size).view(1)) directly inside the graph capture. This worked successfully and fully restored the model’s coherent output without breaking graph logic. Experimented with MLP Block Sizing: I attempted to increase block_m and num_warps in the 1-bit Triton kernel (mxfp_lowbit_selected_swiglu) to reduce redundant memory loads of the intermediate x tensor. Unfortunately, register limits and memory layout meant it actually resulted in worse throughput, so I reverted those changes. Experimented with Attention Loop Early Exit: The single_token_gqa_attention_kernel is statically unrolled up to token_bucket (256). I tried adding a dynamic while loop to break early for short context sizes, but Triton’s compiler handles static for loops much better. reached around 65tk/s on gpt-oss-20b, constantly improvising MoE performance, next ima lock in for dense models but for now on MoE"}, {"post_id": 32489, "ts": "2026-07-21T18:25:21Z", "hours": 3.3508, "text": "Implemented a huge list of fixes Lazy page-ID tensor resolution after quantization Storage-alias-aware VRAM accounting Correct affine INT4 partial-group quantization KV sequence continuity checks Free-page geometry invalidation Canonical LM-head bias and final-softcap handling Certified shortlist logic with exact fallback Gemma-style attention scaling/softcap fixes Removal of hot-path CUDA scalar tensor allocations Device normalization for “cuda”, “cuda:N”, and torch.device Profile separation has been reconnected and different profiles select different kernels. Paged KV storage exists through SlabbedKVCache. A prior paged-attention slowdown was caused by GPU synchronization from .item() calls in SlabbedKVCache.append(), not by paged addressing itself. Logical page ownership is now tracked CPU-side to avoid those synchronizations. Paged attention has measured approximately: Materialized: 55.1 tok/s Paged: 57.5 tok/s on a relevant smaller models"}, {"post_id": 32108, "ts": "2026-07-21T01:27:17Z", "hours": 10.3133, "text": "Devlog-idk atp Well i said that i would stop working on this project last devlog, butttt, i just saw this https://github.com/random-unknown-username/Thintensor/issues/1 Someone tried thintensor on a 128gb unified ram DGX spark, ANDDDDD now i wanna make it good enough like so its a finished thing"}, {"post_id": 28811, "ts": "2026-07-15T09:45:15Z", "hours": 0.805, "text": "Final devlog: I would be moving from this project to other cool stuff i have in mind, the final benchmarks i got and everything, is pushed, had to do a lot of improvements to get bigger models running just as good as small ones I know there can be a lot of other optmizations, but maybe a few months later ill come back to this, but for now, its gonna stay as is."}, {"post_id": 28164, "ts": "2026-07-14T09:02:15Z", "hours": 13.7189, "text": "This devlog retains the apples-to-apples GPT-OSS control plus fresh Qwen3.5-9B, Llama 3.2 11B text-path, OpenReasoning-Nemotron-14B, and Phi-4 A LOT of optimizations were done to achive this results and 100s of benchmarks in different profiles and stuff, to get to this final table"}, {"post_id": 26560, "ts": "2026-07-11T13:36:08Z", "hours": 2.2911, "text": "ThinRuntime GPT-OSS-20B now achieves: 50.3445 tok/s median across three explicit 200-token runs. llama.cpp b9964 Q4_K_M: 40.3631 tok/s mean. ThinRuntime is 24.73% faster. Exact embedding and LM head; Q1/Q2 applies only to experts. Zero expert transfers during decode. Top-1 unchanged through step 4. Cosine: 0.987376 step 1, 0.983299 step 4. Accepted one-step configuration: 0.991415 cosine. llama.cpp Q4_K_M source-relative cosine: 0.792350."}, {"post_id": 26399, "ts": "2026-07-11T05:13:04Z", "hours": 7.2128, "text": "Worked over a LOT of stuff, like doing apples to apples comparisions of models such as LLama 11b vision instruct, So over time I fixed a lot of stuff added a new profile, that quants and quants and quants all layers till the model fits your VRAM, it doesnt care if the model is 20gb in weigths and you have a 8gb vram, it will quant and make it fit So testing this autofit profile on LLama 11b vision instruct, heres what i found it hit a cosine of 0.939758 and around 24tk/s on a 200 token test Similarly i tested ollama Llama 11b vision instruct with q4_k_m quant, it got a cosine close to 0.720495 i would say it would be more closer to 0.8 because this cosine was for only top 20 logprobes that ollama exposes This was done on 8gb vram rtx 5050 laptop 32gb ddr 5 ryzen 7 250 arch linux and the comparision is apples to apples because the thinruntime also quanted the model aggressively"}, {"post_id": 25725, "ts": "2026-07-10T05:02:15Z", "hours": 1.8908, "text": "Devlog: Resolving GPU Memory Corruption & CUDA Assertions on Wide Matvecs 1. The Symptoms When running inference/benchmarks on unquantized models (like Qwen3.5-9B) using the Triton backend on laptop GPUs (e.g., RTX 5050), the runtime encountered two asynchronous CUDA faults: • cudaErrorIllegalAddress (Illegal memory access) during cache eviction. • device-side assert triggered ( indexSelectSmallIndex assertion failed) during embedding vocabulary lookups. 2. The Root Cause (Resource Starvation & Memory Corruption) Wide Layer Geometries: In Qwen3.5, the projection matrices (Query, Key, Value) have a columns dimension of cols = 3584 . Triton Padded Tiling: Triton pads non-power-of-two shapes to the next power of two ( BLOCK_N = 4096 ). Static Tile Size: The default Triton config mapping uses BLOCK_M = 64 for wide matrices. This instructs Triton to compile a kernel loading a massive static tile size of 64 × 4096 = 262,144 elements. Register & Shared Memory Overflow: In FP32 accumulation, this tile requires 1 MB of memory per thread block. However, laptop GPU streaming multiprocessors (SMs) have a physical hardware limit of 96KB–100KB of shared memory/register files. The Failure Cascade: The compiler failed to allocate resources cleanly, resulting in severe register spills and memory read violations. Triton silently returned corrupted/NaN outputs. The subsequent argmax logit lookup generated a garbage token index (out of bounds), which triggered the PyTorch device-side assertion on the next step. 3. The Fix (Dynamic Chunked Looping) To prevent resource starvation, we modified Triton’s launching configuration in triton_kernels.py: Wide Column Routing: Added a check to detect if cols > 2048 . Looped Execution: Instead of loading the entire 4096 columns block statically, we force the kernel to execute _matvec_looped_kernel using a chunk size of BLOCK_N = 512 . Memory Optimization: The kernel loops through the columns sequentially in chunks of 512. This drops the tile size memory requirement per block to under 64 KB, which safely fits inside any laptop GPU’s physical SM limits. 4. Results I am currently running the final profiles ( max-performance and max-max-perf ). Let me check on the status!"}, {"post_id": 25311, "ts": "2026-07-09T15:03:13Z", "hours": 0.8025, "text": "Posted about this on reddit! https://www.reddit.com/r/LocalLLM/comments/1uqr1o3/i_made_a_llm_storage_format_that_makes_llms_run/ Got a lot of feedback, gonna try to work over it over the next few weeks"}, {"post_id": 24643, "ts": "2026-07-08T11:18:54Z", "hours": 0.3739, "text": "Final benchmarks Smaller models have lower cosine because there are like really small like 1B but, some archs are still not fully optimized to run at a good bit faster speed, ik, but i would want to do a ship before working on getting the speed up on those"}, {"post_id": 24238, "ts": "2026-07-07T17:44:41Z", "hours": 0.9025, "text": "Finished benchmarking a few more models Hitting really really good tk/s when compared to hf that even fails to load the models on my 8gb vram, so its a HUGE improvement for gpu poor ppl like me 😭 Reason a lot less improvement for many models is that, each model has a different structure and i havent been able to make a generalized algorithm that would work for all, so for now, we are working with just a simple implementation Benchmark Methodology and Metrics Calculation To ensure accurate, robust, and reproducible results, the benchmarking and correctness scoring flow is executed as follows: 1. Benchmark Execution Workflow Benchmarks are run in isolated, dedicated Python processes for each engine (ThinTensor vs. Hugging Face Transformers) to prevent memory leakage or process interference: ThinTensor Baseline : The model is loaded via the thin_runtime.py engine. Weight Fit Planning : The runtime runs _automatic_fit_plan to estimate weight size. If the model’s weights do not fit within the available GPU VRAM (accounting for system/display manager overhead), it dynamically configures streaming weight residency ( --weight-residency stream ) and streams layers/experts block-by-block from CPU/RAM to the GPU. If the weights fit, it uses fully resident weights ( --weight-residency all ). Timing : Prefills the prompt (default “Hello”), decodes a number of warmup tokens (default 10) to initialize caches and compile/warm up Triton kernels, and then times the next decode steps (default 200) using wall-clock time ( time.perf_counter() ). Transformers (Hugging Face) Baseline : The model is loaded via a dedicated script bench_hf_transformers_decode.py in BF16 precision. RAM/CPU Offloading : For larger models (e.g. Gemma-4-E2B, OLMoE), loading the model fully on memory-constrained GPUs (like the RTX 5050 Laptop GPU with 7.57 GiB VRAM) causes CUDA OOM. To prevent OOM, RAM offloading is enabled via device_map=\"auto\" . Weights that exceed VRAM capacity are kept in CPU system RAM and loaded/swapped as needed. Timing : Like ThinTensor, it pre-runs a prompt prefill, decodes warmup tokens (default 10), and then times steps (default 200) decode steps. The decode loop avoids GPU-to-CPU synchronization (e.g. calling .item() inside the timed loop) to measure pure GPU decoding speed. 2. Metrics & Scores Calculation Thin/HF Peak GiB (Peak GPU Memory) : Tracks peak allocated VRAM in GiB using torch.cuda.max_memory_allocated() . This measures active tensors allocated by PyTorch’s allocator during the decode phase (excluding unallocated cache reserve or general display server memory). Min Cosine (Cosine Similarity) : In compare_hf_thin_logits.py , the logits of the final linear projection layer are collected for both models. Cosine similarity is calculated for the target token index at each step. The minimum cosine similarity found across all decode steps (e.g., step 1 and step 10) and prefill lengths (e.g., 1 and 128) is reported. Top-1 Match : A boolean check indicating whether the token ID with the highest probability (highest logit value) is identical between ThinTensor and HF at all decode steps. Top-5 Set : A boolean check indicating whether the set of top-5 highest-probability token IDs is identical between the two models at all steps (ignoring their internal sorted order). Top-5 Order : A boolean check indicating whether the exact sorted order of the top-5 token IDs matches between ThinTensor and HF at all steps. KV Retention : Specifies the KV cache precision format (e.g. full BF16 )."}, {"post_id": 24052, "ts": "2026-07-07T10:55:07Z", "hours": 5.2325, "text": "Dev Log #4 — 91–96 tok/s with Selective MXFP4 This was the first ThinTensor run that felt genuinely fast. On SmolLM3-3B, the selective MXFP4 gate/up profile reached around: ~91–96 tok/s and on the strong tested record it still preserved: cosine_similarity: 0.9994624257087708 top1_same: true top5_overlap: 0.8 generated_token_match_rate: 0.875 KV retention: full BF16 That cosine is extremely close to the HF BF16 reference: 1.0 - 0.9994624257087708 = 0.0005375742912292 So the run was only about 0.054% away from perfect cosine on that tested checkpoint. Why this was not just normal quantization The profile was selective: MXFP4 gate/up layers: 0:24 MXFP4 row postscale: enabled LM head: FP8 guarded path KV cache: full BF16 attention path: causal KV QKV/O/down: not blindly pushed into MXFP4 A full MXFP4 sweep over QKV, O, down, and gate/up was fast, but it destroyed the logits. That proved the obvious thing: fewer bytes alone is not enough. ThinTensor’s win comes from being role-aware. The runtime knows what each tensor does: Q / K / V O projection gate projection up projection down projection norm embedding LM head KV cache That means the runtime can apply aggressive precision only to the parts that tolerate it. For this result, the safe target was the MLP gate/up path. Why gate/up was the right target Single-token decoding is mostly a weight-read problem. Tthe goal became: reduce gate/up bytes keep attention stable keep KV exact keep LM head guarded preserve token ranking That is exactly what the selective MXFP4 profile does. It uses MXFP4 on the gate/up projections for layers 0:24 , but it does not blindly lower every sensitive path. Where Blackwell helps The test GPU is an RTX 5050 laptop GPU, which is Blackwell. That matters because Blackwell has native low-precision paths for FP4/MXFP4-style execution. ThinTensor uses this through Triton kernels that treat MXFP4 as an execution format, not just a smaller storage format. The idea is: store/read fewer bytes use block scales multiply against BF16 activations accumulate safely then apply row postscale The goal is to make each token cheaper to decode while keeping the output distribution close to HF BF16. The code side The relevant code is built around these ideas: 1. Honest quantization descriptors The QuantizationDescriptor describes the source format: method storage_dtype bits group_size scale_dtype zero_point modules_to_not_convert source_config For example: INT4 != FP4 Q8 != FP8 MXFP4 != generic Q4 The precision_ladder() function makes that explicit. It lists safe choices, opt-in choices, and lossy choices. So instead of silently lowering precision, the runtime can say: preserve native format fallback to BF16 or require explicit validation before requantization 2. Execution planning plan_quantization() decides what should happen at runtime. It can choose: preserve source storage use native kernel dequantize to BF16 or reject unsupported requantization The important flag is this: exact_storage_preserved If this is true, the runtime is using the source encoding directly. Whats next I would have to implement all mainstream model archs manually because all are diff, and like right now you can see, there are a lot of models that are heavily un-optimized Also im messaging stardance team on slack these devlogs too smol for me"}, {"post_id": 22313, "ts": "2026-07-04T18:31:05Z", "hours": 0.8797, "text": "Just hit 91tk/s with “cosine_similarity”: 0.9994624257087708 its actually crazy its like 5x faster the hf full devlog comming soon! ITS LIKE 0.054% away from perfect!!! The selective MXFP4 gate/up profile reached ~96 tok/s while preserving top-1 on the tested SmolLM3-3B through my thintensor runtimeeeee Full DevLogs gonna be crazy"}, {"post_id": 22113, "ts": "2026-07-04T12:07:02Z", "hours": 0.4494, "text": "Initial benchmarks based on some testing on a 3B model Why response similarity? Because we are making a storage format not “just” a runtime, so we need to ensure the model we are optimizing using thintensor runtime it HAS to be replying with the same responses like the original model! So with casual Kv implemented these are the benchmarks i gathered, if you wanna learn what quality fp8 is read my last devlog :D PS- the vram usage on our ThinTensor quality FP8 is just 500 mb more than the q8 even though there is a HUGE difference in the response similarity"}, {"post_id": 22063, "ts": "2026-07-04T09:46:10Z", "hours": 7.5944, "text": "Dev Log #3 — SmolLM3-3B Results SmolLM3-3B was the first real test of ThinTensor as an inference runtime. The baseline was Hugging Face BF16 on my RTX 5050 laptop GPU: HF BF16: ~17.8 tok/s ThinTensor BF16 reached: ThinTensor BF16: ~32–33 tok/s with cosine around 0.999 , meaning the logits stayed extremely close to the original SafeTensors/HF path. That matters because a storage/runtime format should not make the model noticeably worse. Then came the quality FP8 profile: ThinTensor quality FP8: ~46–48 tok/s This was not “quantize everything.” The profile was selective: gate/up projections: FP8 middle down projections: FP8 attention path: BF16 O-proj: BF16 LM head: BF16 KV cache: BF16 ThinTensor can do this because the .thin manifest and execution tape know tensor roles: Q, K, V, O, gate, up, down, norm, embedding, LM head, etc. The runtime can then lower precision only where the model tolerates it, while keeping sensitive paths in BF16. The kernel side reflects this. Attention uses single-token GQA and maps each query head to the right KV head: head = tl . program_id ( 0 ) kv_head = head // ( heads // kv_heads ) scores = tl . sum ( key * q [ None , :], axis = 1 ) * scale The FP8 MLP path uses scaled matvecs: w = tl . load ( weight + offs_m [:, None ] * stride_wm + offs_n [ None , :]) xv = tl . load ( x + offs_n ). to ( tl . float32 ) scale = tl . load ( scales + offs_m ). to ( tl . float32 ) acc = tl . sum ( w * xv [ None , :], axis = 1 ) * scale In one full-vocab centered-logit comparison: GGUF Q8_0 min cosine: 0.952666 ThinTensor BF16 min cosine: 0.999596 ThinTensor quality FP8 min cosine: 0.995366 So ThinTensor quality FP8 stayed much closer to BF16 than the measured Q8 path, while staying in the same speed class. Final speed table: HF BF16: ~17.8 tok/s ThinTensor BF16: ~32–33 tok/s ThinTensor quality FP8: ~46–48 tok/s Ollama / GGUF Q8_0: ~44.1 tok/s Headline: ThinTensor BF16 was ~1.8x faster than HF BF16. ThinTensor quality FP8 was ~2.6x faster than HF BF16. ThinTensor quality FP8 was faster than the measured Q8 baseline while preserving much better logit fidelity. This is where ThinTensor stopped being just an archive experiment and started looking like a real inference runtime :D"}, {"post_id": 20838, "ts": "2026-07-02T15:28:02Z", "hours": 1.5392, "text": "Js got to know that devlogs longer than 10hrs are stripped to 10 😭, i cant have more than 4k char so bear with me theres a LOT to tell that im not able to fit, but ill try my best anyways Dev Log #2 — Converting SafeTensors Into .thin (had to cut so much explaination bcs i HATE THE CHAR LIMIT, id add them in another devlog) The main conversion flow is: pub fn convert_hf ( options : ConvertHfOptions ) -> Result < ConvertHfResult > { let config : Value = serde_json :: from_reader ( File :: open ( options .hf_dir .join ( \"config.json\" )) ? ) ? ; let safetensor_paths = collect_safetensors ( & options .hf_dir ) ? ; let tensors = collect_tensors ( & safetensor_paths ) ? ; let layers = required_u32 ( & config , \"num_hidden_layers\" ) ? ; let model = build_model_spec ( & config , layers , & tensors , & options , & mut warnings ) ? ; let pages = build_pages ( & tensors , & config ) ? ; let execution_tape = build_execution_tape ( layers , & tensors , & mut warnings ) ? ; let manifest = Manifest { format : FORMAT_NAME .to_string (), version : FORMAT_VERSION , model , execution_tape , pages , memory_plan : build_memory_plan ( & config , & tensors ), }; write_archive_pages ( & options .out_path , & manifest , & archive_pages ) ? ; let archive = Archive :: open ( & options .out_path ) ? ; verify_archive ( & archive ) ? ; Ok ( ConvertHfResult { archive , warnings }) } The converter memory-maps each SafeTensors file read-only: let mmap = unsafe { Mmap :: map ( & file ) ? }; let safetensors = SafeTensors :: deserialize ( & mmap ) ? ; let base = mmap .as_ptr () as usize ; Then every tensor becomes a page candidate. The converter records where the tensor bytes live inside the mapped file: let data = tensor .data (); let offset = ( data .as_ptr () as usize ) .checked_sub ( base ) ? ; and stores: struct TensorPage { id : String , path : PathBuf , offset : u64 , size : u64 , checksum : [ u8 ; 32 ], dtype : String , shape : Vec < u64 > , } This avoids rebuilding every tensor in memory. The archive can later copy the original byte range directly: ArchivePageSource :: FileRange { path : tensor .path .clone (), offset : tensor .offset , } After collecting raw tensor data, the converter builds the model spec. It extracts or infers things like hidden size, layer count, attention heads, KV heads, head dimension, RoPE settings, vocab size, activation type, quantization config, and required runtime operators. One important field is attention type: let attention_kind = if kv_heads == heads { \"mha\" } else if kv_heads == 1 { \"mqa\" } else { \"gqa\" }; This matters because many modern decoder models use grouped-query attention. If the runtime only sees shapes but does not understand Q heads vs KV heads, causal attention can be wrong while still looking structurally valid. The converter also records required operators: let mut required_operators = vec! [ \"embedding\" .to_string (), \"rms_norm\" .to_string (), \"qkv_projection\" .to_string (), \"rope\" .to_string (), format! ( \"{attention_kind}_attention\" ), \"o_projection\" .to_string (), \"lm_head\" .to_string (), ]; For dense MLPs it adds: gated_activation down_projection For MoE models it records router and expert stages instead. the rest would be explained in another devlog, i hate the char limit (had to re-write like 10 times btw)"}, {"post_id": 20663, "ts": "2026-07-02T10:03:23Z", "hours": 14.5956, "text": "Dev Log #1 — Why ThinTensor Exists SafeTensors is already a very good format for what it was designed to do: store tensors safely. It keeps tensor metadata simple. For normal model distribution, that is enough. The problem starts when the tensor file becomes the runtime boundary. That is enough if another framework already knows the model class and execution graph. But for an inference runtime, especially one focused on single-token decode, those fields are not enough. The runtime needs to know what each tensor means . The .thin Format The first .thin archive is intentionally simple: .thin = fixed header + JSON manifest + page table + raw page data The Rust implementation defines the archive identity and header size directly: pub const MAGIC: &[u8; 8] = b\"THINv0\\0\\0\"; pub const HEADER_LEN: u32 = 88; The header stores the physical structure of the archive: pub struct Header { pub header_len: u32, pub version: u32, pub manifest_off: u64, pub manifest_len: u64, pub page_table_off: u64, pub page_count: u64, pub data_off: u64, pub archive_hash: [u8; 32], } This lets the loader open the file without guessing. It reads the header, jumps to the manifest, then reads the page table, then maps the raw page data. The manifest is JSON because the early format needed to stay inspectable. It contains the model-level information needed to reconstruct decode: architecture hidden size number of layers attention heads KV heads head dimension vocabulary size RoPE settings tensor names tensor shapes tensor dtypes tensor roles quantization metadata runtime/backend hints validation metadata The page table connects the manifest to real bytes inside the archive: pub struct PageTableRecord { pub page_id: String, pub offset: u64, pub stored_size: u64, pub raw_size: u64, pub flags: u32, pub checksum: [u8; 32], } A page record gives the runtime a verified byte range, not just a tensor name. This matters because pages can later be scheduled, streamed, cached, kept on CPU, moved to GPU, or assigned different execution policies. Packing and Verification The packer does not blindly write files into an archive. It validates the manifest first: let report = validate_manifest(&manifest); if !report.is_ok() { bail!(\"manifest invalid:\\n{}\", report.errors.join(\"\\n\")); } Then every page declared in the manifest must exist and match its declared size: if bytes.len() as u64 != page.size { bail!(\"page declared size does not match file size\"); } It also verifies the page checksum: let checksum = blake3::hash(&bytes); if checksum.as_bytes().as_slice() != expected.as_slice() { bail!(\"page checksum does not match manifest\"); } Only after validation does the writer emit the archive: write_header(&mut file, &header)?; file.write_all(&manifest_bytes)?; for record in &records { write_page_table_record(&mut file, record)?; } for page in pages { write_page_source(&mut file, page)?; } So the final file is structured as: [ header ] [ manifest JSON ] [ page table records ] [ raw page blobs ]"}]...
|
Title: Thintensors by @satvikhardat | Stardance
D Title: Thintensors by @satvikhardat | Stardance
Devlogs:
Dev Log #1 — Why ThinTensor Exists SafeTensors is already a very good format for what it was designed to do: store tensors safely. It keeps tensor metadata simple. For normal model distribution, that is enough. The problem starts when the tensor file becomes the runtime boundary. That is enough if another framework already knows the model class and execution graph. But for an inference runtime, especially one focused on single-token decode, those fields are not enough. The runtime needs to know what each tensor means . The .thin Format The first .thin archive is intentionally simple: .thin = fixed header + JSON manifest + page table + raw page data The Rust implementation defines the archive identity and header size directly: pub const MAGIC: &[u8; 8] = b"THINv0\0\0"; pub const HEADER_LEN: u32 = 88; The header stores the physical structure of the archive: pub struct Header { pub header_len: u32, pub version: u32, pub manifest_off: u64, pub manifest_len: u64, pub page_table_off: u64, pub page_count: u64, pub data_off: u64, pub archive_hash: [u8; 32], } This lets the loader open the file without guessing. It reads the header, jumps to the manifest, then reads the page table, then maps the raw page data. The manifest is JSON because the early format needed to stay inspectable. It contains the model-level information needed to reconstruct decode: architecture hidden size number of layers attention heads KV heads head dimension vocabulary size RoPE settings tensor names tensor shapes tensor dtypes tensor roles quantization metadata runtime/backend hints validation metadata The page table connects the manifest to real bytes inside the archive: pub struct PageTableRecord { pub page_id: String, pub offset: u64, pub stored_size: u64, pub raw_size: u64, pub flags: u32, pub checksum: [u8; 32], } A page record gives the runtime a verified byte range, not just a tensor name. This matters because pages can later be scheduled, streamed, cached, kept on CPU, moved to GPU, or assigned different execution policies. Packing and Verification The packer does not blindly write files into an archive. It validates the manifest first: let report = validate_manifest(&manifest); if !report.is_ok() { bail!("manifest invalid:\n{}", report.errors.join("\n")); } Then every page declared in the manifest must exist and match its declared size: if bytes.len() as u64 != page.size { bail!("page declared size does not match file size"); } It also verifies the page checksum: let checksum = blake3::hash(&bytes); if checksum.as_bytes().as_slice() != expected.as_slice() { bail!("page checksum does not match manifest"); } Only after validation does the writer emit the archive: write_header(&mut file, &header)?; file.write_all(&manifest_bytes)?; for record in &records { write_page_table_record(&mut file, record)?; } for page in pages { write_page_source(&mut file, page)?; } So the final file is structured as: [ header ] [ manifest JSON ] [ page table records ] [ raw page blobs ]
Js got to know that devlogs longer than 10hrs are stripped to 10 😭, i cant have more than 4k char so bear with me theres a LOT to tell that im not able to fit, but ill try my best anyways Dev Log #2 — Converting SafeTensors Into .thin (had to cut so much explaination bcs i HATE THE CHAR LIMIT, id add them in another devlog) The main conversion flow is: pub fn convert_hf ( options : ConvertHfOptions ) -> Result < ConvertHfResult > { let config : Value = serde_json :: from_reader ( File :: open ( options .hf_dir .join ( "config.json" )) ? ) ? ; let safetensor_paths = collect_safetensors ( & options .hf_dir ) ? ; let tensors = collect_tensors ( & safetensor_paths ) ? ; let layers = required_u32 ( & config , "num_hidden_layers" ) ? ; let model = build_model_spec ( & config , layers , & tensors , & options , & mut warnings ) ? ; let pages = build_pages ( & tensors , & config ) ? ; let execution_tape = build_execution_tape ( layers , & tensors , & mut warnings ) ? ; let manifest = Manifest { format : FORMAT_NAME .to_string (), version : FORMAT_VERSION , model , execution_tape , pages , memory_plan : build_memory_plan ( & config , & tensors ), }; write_archive_pages ( & options .out_path , & manifest , & archive_pages ) ? ; let archive = Archive :: open ( & options .out_path ) ? ; verify_archive ( & archive ) ? ; Ok ( ConvertHfResult { archive , warnings }) } The converter memory-maps each SafeTensors file read-only: let mmap = unsafe { Mmap :: map ( & file ) ? }; let safetensors = SafeTensors :: deserialize ( & mmap ) ? ; let base = mmap .as_ptr () as usize ; Then every tensor becomes a page candidate. The converter records where the tensor bytes live inside the mapped file: let data = tensor .data (); let offset = ( data .as_ptr () as usize ) .checked_sub ( base ) ? ; and stores: struct TensorPage { id : String , path : PathBuf , offset : u64 , size : u64 , checksum : [ u8 ; 32 ], dtype : String , shape : Vec < u64 > , } This avoids rebuilding every tensor in memory. The archive can later copy the original byte range directly: ArchivePageSource :: FileRange { path : tensor .path .clone (), offset : tensor .offset , } After collecting raw tensor data, the converter builds the model spec. It extracts or infers things like hidden size, layer count, attention heads, KV heads, head dimension, RoPE settings, vocab size, activation type, quantization config, and required runtime operators. One important field is attention type: let attention_kind = if kv_heads == heads { "mha" } else if kv_heads == 1 { "mqa" } else { "gqa" }; This matters because many modern decoder models use grouped-query attention. If the runtime only sees shapes but does not understand Q heads vs KV heads, causal attention can be wrong while still looking structurally valid. The converter also records required operators: let mut required_operators = vec! [ "embedding" .to_string (), "rms_norm" .to_string (), "qkv_projection" .to_string (), "rope" .to_string (), format! ( "{attention_kind}_attention" ), "o_projection" .to_string (), "lm_head" .to_string (), ]; For dense MLPs it adds: gated_activation down_projection For MoE models it records router and expert stages instead. the rest would be explained in another devlog, i hate the char limit (had to re-write like 10 times btw)
Dev Log #3 — SmolLM3-3B Results SmolLM3-3B was the first real test of ThinTensor as an inference runtime. The baseline was Hugging Face BF16 on my RTX 5050 laptop GPU: HF BF16: ~17.8 tok/s ThinTensor BF16 reached: ThinTensor BF16: ~32–33 tok/s with cosine around 0.999 , meaning the logits stayed extremely close to the original SafeTensors/HF path. That matters because a storage/runtime format should not make the model noticeably worse. Then came the quality FP8 profile: ThinTensor quality FP8: ~46–48 tok/s This was not “quantize everything.” The profile was selective: gate/up projections: FP8 middle down projections: FP8 attention path: BF16 O-proj: BF16 LM head: BF16 KV cache: BF16 ThinTensor can do this because the .thin manifest and execution tape know tensor roles: Q, K, V, O, gate, up, down, norm, embedding, LM head, etc. The runtime can then lower precision only where the model tolerates it, while keeping sensitive paths in BF16. The kernel side reflects this. Attention uses single-token GQA and maps each query head to the right KV head: head = tl . program_id ( 0 ) kv_head = head // ( heads // kv_heads ) scores = tl . sum ( key * q [ None , :], axis = 1 ) * scale The FP8 MLP path uses scaled matvecs: w = tl . load ( weight + offs_m [:, None ] * stride_wm + offs_n [ None , :]) xv = tl . load ( x + offs_n ). to ( tl . float32 ) scale = tl . load ( scales + offs_m ). to ( tl . float32 ) acc = tl . sum ( w * xv [ None , :], axis = 1 ) * scale In one full-vocab centered-logit comparison: GGUF Q8_0 min cosine: 0.952666 ThinTensor BF16 min cosine: 0.999596 ThinTensor quality FP8 min cosine: 0.995366 So ThinTensor quality FP8 stayed much closer to BF16 than the measured Q8 path, while staying in the same speed class. Final speed table: HF BF16: ~17.8 tok/s ThinTensor BF16: ~32–33 tok/s ThinTensor quality FP8: ~46–48 tok/s Ollama / GGUF Q8_0: ~44.1 tok/s Headline: ThinTensor BF16 was ~1.8x faster than HF BF16. ThinTensor quality FP8 was ~2.6x faster than HF BF16. ThinTensor quality FP8 was faster than the measured Q8 baseline while preserving much better logit fidelity. This is where ThinTensor stopped being just an archive experiment and started looking like a real inference runtime :D
Initial benchmarks based on some testing on a 3B model Why response similarity? Because we are making a storage format not “just” a runtime, so we need to ensure the model we are optimizing using thintensor runtime it HAS to be replying with the same responses like the original model! So with casual Kv implemented these are the benchmarks i gathered, if you wanna learn what quality fp8 is read my last devlog :D PS- the vram usage on our ThinTensor quality FP8 is just 500 mb more than the q8 even though there is a HUGE difference in the response similarity
Just hit 91tk/s with “cosine_similarity”: 0.9994624257087708 its actually crazy its like 5x faster the hf full devlog comming soon! ITS LIKE 0.054% away from perfect!!! The selective MXFP4 gate/up profile reached ~96 tok/s while preserving top-1 on the tested SmolLM3-3B through my thintensor runtimeeeee Full DevLogs gonna be crazy
Dev Log #4 — 91–96 tok/s with Selective MXFP4 This was the first ThinTensor run that felt genuinely fast. On SmolLM3-3B, the selective MXFP4 gate/up profile reached around: ~91–96 tok/s and on the strong tested record it still preserved: cosine_similarity: 0.9994624257087708 top1_same: true top5_overlap: 0.8 generated_token_match_rate: 0.875 KV retention: full BF16 That cosine is extremely close to the HF BF16 reference: 1.0 - 0.9994624257087708 = 0.0005375742912292 So the run was only about 0.054% away from perfect cosine on that tested checkpoint. Why this was not just normal quantization The profile was selective: MXFP4 gate/up layers: 0:24 MXFP4 row postscale: enabled LM head: FP8 guarded path KV cache: full BF16 attention path: causal KV QKV/O/down: not blindly pushed into MXFP4 A full MXFP4 sweep over QKV, O, down, and gate/up was fast, but it destroyed the logits. That proved the obvious thing: fewer bytes alone is not enough. ThinTensor’s win comes from being role-aware. The runtime knows what each tensor does: Q / K / V O projection gate projection up projection down projection norm embedding LM head KV cache That means the runtime can apply aggressive precision only to the parts that tolerate it. For this result, the safe target was the MLP gate/up path. Why gate/up was the right target Single-token decoding is mostly a weight-read problem. Tthe goal became: reduce gate/up bytes keep attention stable keep KV exact keep LM head guarded preserve token ranking That is exactly what the selective MXFP4 profile does. It uses MXFP4 on the gate/up projections for layers 0:24 , but it does not blindly lower every sensitive path. Where Blackwell helps The test GPU is an RTX 5050 laptop GPU, which is Blackwell. That matters because Blackwell has native low-precision paths for FP4/MXFP4-style execution. ThinTensor uses this through Triton kernels that treat MXFP4 as an execution format, not just a smaller storage format. The idea is: store/read fewer bytes use block scales multiply against BF16 activations accumulate safely then apply row postscale The goal is to make each token cheaper to decode while keeping the output distribution close to HF BF16. The code side The relevant code is built around these ideas: 1. Honest quantization descriptors The QuantizationDescriptor describes the source format: method storage_dtype bits group_size scale_dtype zero_point modules_to_not_convert source_config For example: INT4 != FP4 Q8 != FP8 MXFP4 != generic Q4 The precision_ladder() function makes that explicit. It lists safe choices, opt-in choices, and lossy choices. So instead of silently lowering precision, the runtime can say: preserve native format fallback to BF16 or require explicit validation before requantization 2. Execution planning plan_quantization() decides what should happen at runtime. It can choose: preserve source storage use native kernel dequantize to BF16 or reject unsupported requantization The important flag is this: exact_storage_preserved If this is true, the runtime is using the source encoding directly. Whats next I would have to implement all mainstream model archs manually because all are diff, and like right now you can see, there are a lot of models that are heavily un-optimized Also im messaging stardance team on slack these devlogs too smol for me
Finished benchmarking a few more models Hitting really really good tk/s when compared to hf that even fails to load the models on my 8gb vram, so its a HUGE improvement for gpu poor ppl like me 😭 Reason a lot less improvement for many models is that, each model has a different structure and i havent been able to make a generalized algorithm that would work for all, so for now, we are working with just a simple implementation Benchmark Methodology and Metrics Calculation To ensure accurate, robust, and reproducible results, the benchmarking and correctness scoring flow is executed as follows: 1. Benchmark Execution Workflow Benchmarks are run in isolated, dedicated Python processes for each engine (ThinTensor vs. Hugging Face Transformers) to prevent memory leakage or process interference: ThinTensor Baseline : The model is loaded via the thin_runtime.py engine. Weight Fit Planning : The runtime runs _automatic_fit_plan to estimate weight size. If the model’s weights do not fit within the available GPU VRAM (accounting for system/display manager overhead), it dynamically configures streaming weight residency ( --weight-residency stream ) and streams layers/experts block-by-block from CPU/RAM to the GPU. If the weights fit, it uses fully resident weights ( --weight-residency all ). Timing : Prefills the prompt (default “Hello”), decodes a number of warmup tokens (default 10) to initialize caches and compile/warm up Triton kernels, and then times the next decode steps (default 200) using wall-clock time ( time.perf_counter() ). Transformers (Hugging Face) Baseline : The model is loaded via a dedicated script bench_hf_transformers_decode.py in BF16 precision. RAM/CPU Offloading : For larger models (e.g. Gemma-4-E2B, OLMoE), loading the model fully on memory-constrained GPUs (like the RTX 5050 Laptop GPU with 7.57 GiB VRAM) causes CUDA OOM. To prevent OOM, RAM offloading is enabled via device_map="auto" . Weights that exceed VRAM capacity are kept in CPU system RAM and loaded/swapped as needed. Timing : Like ThinTensor, it pre-runs a prompt prefill, decodes warmup tokens (default 10), and then times steps (default 200) decode steps. The decode loop avoids GPU-to-CPU synchronization (e.g. calling .item() inside the timed loop) to measure pure GPU decoding speed. 2. Metrics & Scores Calculation Thin/HF Peak GiB (Peak GPU Memory) : Tracks peak allocated VRAM in GiB using torch.cuda.max_memory_allocated() . This measures active tensors allocated by PyTorch’s allocator during the decode phase (excluding unallocated cache reserve or general display server memory). Min Cosine (Cosine Similarity) : In compare_hf_thin_logits.py , the logits of the final linear projection layer are collected for both models. Cosine similarity is calculated for the target token index at each step. The minimum cosine similarity found across all decode steps (e.g., step 1 and step 10) and prefill lengths (e.g., 1 and 128) is reported. Top-1 Match : A boolean check indicating whether the token ID with the highest probability (highest logit value) is identical between ThinTensor and HF at all decode steps. Top-5 Set : A boolean check indicating whether the set of top-5 highest-probability token IDs is identical between the two models at all steps (ignoring their internal sorted order). Top-5 Order : A boolean check indicating whether the exact sorted order of the top-5 token IDs matches between ThinTensor and HF at all steps. KV Retention : Specifies the KV cache precision format (e.g. full BF16 ).
Final benchmarks Smaller models have lower cosine because there are like really small like 1B but, some archs are still not fully optimized to run at a good bit faster speed, ik, but i would want to do a ship before working on getting the speed up on those
Posted about this on reddit! https://www.reddit.com/r/LocalLLM/comments/1uqr1o3/i_made_a_llm_storage_format_that_makes_llms_run/ Got a lot of feedback, gonna try to work over it over the next few weeks
Devlog: Resolving GPU Memory Corruption & CUDA Assertions on Wide Matvecs 1. The Symptoms When running inference/benchmarks on unquantized models (like Qwen3.5-9B) using the Triton backend on laptop GPUs (e.g., RTX 5050), the runtime encountered two asynchronous CUDA faults: • cudaErrorIllegalAddress (Illegal memory access) during cache eviction. • device-side assert triggered ( indexSelectSmallIndex assertion failed) during embedding vocabulary lookups. 2. The Root Cause (Resource Starvation & Memory Corruption) Wide Layer Geometries: In Qwen3.5, the projection matrices (Query, Key, Value) have a columns dimension of cols = 3584 . Triton Padded Tiling: Triton pads non-power-of-two shapes to the next power of two ( BLOCK_N = 4096 ). Static Tile Size: The default Triton config mapping uses BLOCK_M = 64 for wide matrices. This instructs Triton to compile a kernel loading a massive static tile size of 64 × 4096 = 262,144 elements. Register & Shared Memory Overflow: In FP32 accumulation, this tile requires 1 MB of memory per thread block. However, laptop GPU streaming multiprocessors (SMs) have a physical hardware limit of 96KB–100KB of shared memory/register files. The Failure Cascade: The compiler failed to allocate resources cleanly, resulting in severe register spills and memory read violations. Triton silently returned corrupted/NaN outputs. The subsequent argmax logit lookup generated a garbage token index (out of bounds), which triggered the PyTorch device-side assertion on the next step. 3. The Fix (Dynamic Chunked Looping) To prevent resource starvation, we modified Triton’s launching configuration in triton_kernels.py: Wide Column Routing: Added a check to detect if cols > 2048 . Looped Execution: Instead of loading the entire 4096 columns block statically, we force the kernel to execute _matvec_looped_kernel using a chunk size of BLOCK_N = 512 . Memory Optimization: The kernel loops through the columns sequentially in chunks of 512. This drops the tile size memory requirement per block to under 64 KB, which safely fits inside any laptop GPU’s physical SM limits. 4. Results I am currently running the final profiles ( max-performance and max-max-perf ). Let me check on the status!
Worked over a LOT of stuff, like doing apples to apples comparisions of models such as LLama 11b vision instruct, So over time I fixed a lot of stuff added a new profile, that quants and quants and quants all layers till the model fits your VRAM, it doesnt care if the model is 20gb in weigths and you have a 8gb vram, it will quant and make it fit So testing this autofit profile on LLama 11b vision instruct, heres what i found it hit a cosine of 0.939758 and around 24tk/s on a 200 token test Similarly i tested ollama Llama 11b vision instruct with q4_k_m quant, it got a cosine close to 0.720495 i would say it would be more closer to 0.8 because this cosine was for only top 20 logprobes that ollama exposes This was done on 8gb vram rtx 5050 laptop 32gb ddr 5 ryzen 7 250 arch linux and the comparision is apples to apples because the thinruntime also quanted the model aggressively
ThinRuntime GPT-OSS-20B now achieves: 50.3445 tok/s median across three explicit 200-token runs. llama.cpp b9964 Q4_K_M: 40.3631 tok/s mean. ThinRuntime is 24.73% faster. Exact embedding and LM head; Q1/Q2 applies only to experts. Zero expert transfers during decode. Top-1 unchanged through step 4. Cosine: 0.987376 step 1, 0.983299 step 4. Accepted one-step configuration: 0.991415 cosine. llama.cpp Q4_K_M source-relative cosine: 0.792350.
This devlog retains the apples-to-apples GPT-OSS control plus fresh Qwen3.5-9B, Llama 3.2 11B text-path, OpenReasoning-Nemotron-14B, and Phi-4 A LOT of optimizations were done to achive this results and 100s of benchmarks in different profiles and stuff, to get to this final table
Final devlog: I would be moving from this project to other cool stuff i have in mind, the final benchmarks i got and everything, is pushed, had to do a lot of improvements to get bigger models running just as good as small ones I know there can be a lot of other optmizations, but maybe a few months later ill come back to this, but for now, its gonna stay as is.
Devlog-idk atp Well i said that i would stop working on this project last devlog, butttt, i just saw this https://github.com/random-unknown-username/Thintensor/issues/1 Someone tried thintensor on a 128gb unified ram DGX spark, ANDDDDD now i wanna make it good enough like so its a finished thing
Implemented a huge list of fixes Lazy page-ID tensor resolution after quantization Storage-alias-aware VRAM accounting Correct affine INT4 partial-group quantization KV sequence continuity checks Free-page geometry invalidation Canonical LM-head bias and final-softcap handling Certified shortlist logic with exact fallback Gemma-style attention scaling/softcap fixes Removal of hot-path CUDA scalar tensor allocations Device normalization for “cuda”, “cuda:N”, and torch.device Profile separation has been reconnected and different profiles select different kernels. Paged KV storage exists through SlabbedKVCache. A prior paged-attention slowdown was caused by GPU synchronization from .item() calls in SlabbedKVCache.append(), not by paged addressing itself. Logical page ownership is now tracked CPU-side to avoid those synchronizations. Paged attention has measured approximately: Materialized: 55.1 tok/s Paged: 57.5 tok/s on a relevant smaller models
What I’ve Done: Fixed KV Cache Indexing in Graph Mode: The previous cudaErrorStreamCaptureUnsupported error and out-of-bounds access were caused by assigning python integers dynamically during capture, and failing to respect block sizing. I modified the KV cache’s _in_graph_mode behavior to compute the tensor-based slot offset dynamically ((slot % block_size).view(1)) directly inside the graph capture. This worked successfully and fully restored the model’s coherent output without breaking graph logic. Experimented with MLP Block Sizing: I attempted to increase block_m and num_warps in the 1-bit Triton kernel (mxfp_lowbit_selected_swiglu) to reduce redundant memory loads of the intermediate x tensor. Unfortunately, register limits and memory layout meant it actually resulted in worse throughput, so I reverted those changes. Experimented with Attention Loop Early Exit: The single_token_gqa_attention_kernel is statically unrolled up to token_bucket (256). I tried adding a dynamic while loop to break early for short context sizes, but Triton’s compiler handles static for loops much better. reached around 65tk/s on gpt-oss-20b, constantly improvising MoE performance, next ima lock in for dense models but for now on MoE
what I did to fix the numerical drift & get some speedups: The Root Cause of the Drift (The Cosine Fix): I discovered that in triton_kernels.py , the tl.dot_scaled call inside _mxfp_lowbit_selected_tensorcore_matvec_kernel (and the mxfp4 variant) had fast_math=True . The fast_math option drops critical precision bits during accumulator addition which was causing the MoE kernels to completely obliterate the trajectory. I disabled it globally using fast_math=False , and this instantly restored our cosine similarity to a perfect 1.000000 over the entire benchmark trajectory. The VRAM Bottleneck: When relying purely on MXFP4 experts, they required over 9.5 GB, breaking the 6.6 GiB budget and forcing the runtime to stream them via PCIe (which tanks performance down to ~5-10tok/s). The Q2 and Q1 low-bit expert decoding kernels actually achieve identical numerical accuracy to the baseline while aggressively packing the weights. The 97.87 tok/s Optimization: I configured bench.py and check_baseline_cosine.py to use: packed_expert_q1_layers="0:24" : All 24 layers of MoE experts are now tightly packed into 1-bit Q1 structures, shrinking the expert memory footprint down to just 2.38 GB (from 9.52 GB). dense_int4_layers="all" : Shrunk the non-expert dense projection weights (Q, K, V, O) into INT4, dropping their footprint from ~1.1 GB to ~0.27 GB. Since the entire model now takes 5.29 GiB (fitting entirely within the 6.6 GiB budget), all layers are pinned directly to VRAM. Because zero layers are streamed (any_streamed=False), the runtime successfully builds the fully fused cuda_graphs execution path, accelerating generation from a crawl to 97.87 tok/s ON gpt-oss-20b. I believe ill be moving to dense models just about now All these issues took SOOO many tests to find
I ammmm tierdd i tried a billionn things over the last 8 hours i just cant seem to understand why gemma4 doesnt want to workkkkk I dont have much to write in this devlog, other than, i am not gonna implement gemma arch for now
ThinTensor Improvements Universal semantic-IR runtime for mixed attention, dense and MoE architectures. Per-tensor precision, kernel and residency planning instead of layer-wide quantization. Production FP8, INT4, MXFP4, Q2 and Q1 quantizers with calibration-aware scoring. Hard ≥0.995 cosine certification with exact routing, greedy-token and KV checks. Qwen3.5 hybrid linear-attention, shared-expert and packed rank-3 MoE support. Durable grouped-INT4 expert sidecars with bounded-RAM, mmap-based construction. Fixed four-matrix Triton projection, cuda / cuda:0 , layer-zero and converter-role bugs. Improved fused kernels, KV caching, expert routing and decode hot paths. Strict cache identity across model, tokenizer, GPU, CUDA, kernels and calibration. Remaining goal: prove ≥30 tok/s on Qwen3.5-35B-A3B at certified ≥0.995 cosine. Getting way better speed on 27B dense models at a cosine that is also way better
Hitting 100hrs and final ship Didnt get time to work on this idea, since quite the while. And it has js about reached the state i can probably get it to MoE arch works, dense models work, cpu/gpu streaming works well, context/kv cache is also dynamically quanted lm_head quants are also there now The motivation really died out because of this project not getting reviewed its been over a month, leaving this as is, tho its not perfect, but it js about has enough features that i wanted Here are the final results after a ton of benchmarking- Phi-4: ThinTensor 28.21 tok/s vs llama.cpp 17.50 tok/s — 1.61× faster (+61.2%). Quality: 0.999949 cosine vs 0.997281. OpenReasoning-Nemotron-14B: ThinTensor 23.79 tok/s vs llama.cpp 19.79 tok/s — 1.20× faster (+20.2%). Quality: 0.999533 vs 0.967140. Llama 3.2 11B: ThinTensor 41.02 tok/s vs llama.cpp 39.82 tok/s — 1.03× faster (+3.0%). Quality: 0.995095 vs 0.991938. Qwen3.5-9B: ThinTensor 43.28 tok/s vs llama.cpp 42.83 tok/s — 1.01× faster (+1.1%). Quality: 0.973334 vs 0.894908. GPT-OSS-20B: ThinTensor 50.34 tok/s vs llama.cpp 40.36 tok/s — 1.25× faster (+24.7%). Quality: 0.983299 vs 0.792350. *all are apples to apples btw Overall: ThinTensor beats llama.cpp Q4 throughput on 5/5 tested architectures , with a geometric-mean speedup of approximately 1.203× . Probably gonna take a break, and learn before comming back to this, after the ship-2 on stardance!
Fixed a few Dense path issues, because the MoE path somehow made the dense path completely usable, fixed a few small one line bugs i got to know from the last ship’s reviews, read to for ship 2!!
Ships:
I made ThinTensor, a runtime-aware LLM archive and inference runtime. Instead of only storing tensor bytes, it stores tensor roles, memory pages, quant metadata, and execution hints so the runtime can choose faster kernels and precision paths. The hardest part was keeping speed gains honest with HF correctness checks. So far it reaches up to ~94 tok/s on SmolLM3-3B with full BF16 KV retention and high logit similarity. After being tested on multiple models, you can get a avg 2x performance increase on most LLM archs, all archs are still not implemented, ik but this is workable with qwen, gemma, some MoE models, and SmolLM and a most others, but it wont be as optimized for all the model types Follow the guide at https://github.com/random-unknown-username/Thintensor#fast-path-setting-up-on-a-new-laptop To install thintensor runtime and use this guide to get a sample qwen model up and running https://github.com/random-unknown-username/Thintensor#quickstart-downloading--running-a-sample-model-qwen-08b
Its a runtime-aware LLM archive format built for fast, efficient inference, This ship basically integrates MoE model paths, that allows you to run models like gpt-oss-20B on speeds and quality faster and better than llama.cpp!! (at q4) its not just the storage format that allows for the improvements, its a combination of different selective layers being quantized with the better storage format, allowing to run inference with higher speed and quality than just simple q8,q4 etc quants. the storage format only gain is only like 10%, but combined with middle out fp8 quants, and even int4 for some performance profiles, it can reach better speeds than the other ways to run inference This does not beat TRT / TRT LM, it does allow for quicker inference, and a more portable solution because for TRT you need to compile the plan (one time) for a few mins before being able to run the model, and it has to be compiled on every machine you run the model on, thintensor allows you to directly have the .thin file and run it on any machine with similar results! and it takes just a few seconds compared to about 30 mins on trt and trt lm reddit post for this project- https://www.reddit.com/r/LocalLLM/comments/1uqr1o3/i_made_a_llm_storage_format_that_makes_llms_run/ independent tester’s view- https://github.com/random-unknown-username/Thintensor/issues/1 Let me know if u find any issues, tried a lot of other models here too, as u can see in the graphs :D let me know of any bugs on slack...
|
1792878673.5936122
|
1793742673.5936122
|
|
47344
|
Project FlowMark by @The_Hedgehog | Stardance
|
The_Hedgehog
|
1
|
106.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-19T22:48:05Z", "hours": 106.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a buoy that can float freely down a river. It has four sensors, pH, conductivity, dissolved organic matter, and turbidity. It constantly uses these sensors to take measurements and sends it to a locally hosted Python Flask server tunneled using Ngrok. After the buoy is collected from the water, the server will analyse the data and find out where the water quality started to worsen, therefore finding out where riverine polution might be. Although the project wasn’t very complicated, I faced many many problems. The most memorable and most fustrating ones: I use a step up module to turn the 4v from my 18650 to 5v for my ESP32 C3 Supermini. But the step up often randomly output over 20v, though it is set for 5v. I later found out that its because a loose connection between my battery and the step up, but the voltage spikes has badly burnt many things in my circuit. The ESP32 C3 Supermini suddenly cannot connect to my computer. I tried holding down boot button, boot and reset, redownload a driver, and trying all the ports on my computer and in Arduino IDE. But it just won’t work. So I changed to a Arduino Nano. But that just made things worse. The Arduino Nano successfully connected to my computer, but it often corrupts recieved UART signals from my cellular module. Later I found out that its because the Arduino Nano’s clock is a bit off for 112500 baud. This made things more complicated because I need to start the UART communication between the Nano and the cellular module at 112500 (since my cellular module is default 112500 when start up), then request the cellular module to turn down to 9600, and then change the Nano UART back to 9600. It did finally work tho. I guess this is the worst nightmare in my project. My project uses a pair of 18650 in parallel, as it can have more power to sustain my buoy for longer. But the cellular module often shut down right after it turns on. It turns out that the celular module can pull up to 2 amps when connecting to the cellular tower and sending messages, which is causing the voltage drop. However, this was weird because the two 18650 cells I had is the Samsung 25R, which has a max discharge of 20 amps. Parallel means that the max discharge become 40 amps, which is wayyyyyyy more than the 2 amps required. So the problem must not be the batteries. Or is it? I suspect that the batteries are fake. They weigh pretty normal, being 44 grams. I checked the imprints on the wrapping, and it did have a legitemate manufacture date code that says someday in 2017 (I forgot which day it was, but it was 2017). And I also took off the battery wrapping, and it did had Samsung factory imprints on the metal. So the battery is good, the cellular module can only take up to 2 amps….. then the problem must be between the cellular module and the battery! And it was. It was the thin jumper wires and breadboard that decreased the voltage when the current increased. Shorter thicker wires solved it. There was actually much more issues, but these are the most memorable ones for me. I am glad that my project turns out to be working, becuase i genuinely thought that it would never work when making it.", "repo": "https://github.com/LukeHuang2026/Project_Flowmark", "demo": ""}]...
|
[{"post_id": 66520, "ts": "202 [{"post_id": 66520, "ts": "2026-09-12T11:13:09Z", "hours": 1.3169, "text": "Today I almsot finished the slides for my presentation for UWEN next week, so I can go there and get some feedback."}, {"post_id": 65872, "ts": "2026-09-11T09:42:46Z", "hours": 3.2531, "text": "Today I finally made my cellular module work, as before it always shut down due to thin wires burning up too much voltage. My free floating buoy is ready for testing!"}, {"post_id": 65294, "ts": "2026-09-10T10:20:11Z", "hours": 3.5017, "text": "Today I tried to power my cellular module with my two 18650 in parallel. It kinda works for a while but then the voltage dips and the module turns itself off. Its most likely the thin wires, and I optimised it as much as I can, but the same thing happens. I will charge my batteries up again and if it still dont’ work I will just skip my MOSFET circuit that turns the module on and off, as this thing still has a bit of thin wires. If it STILL dont’ work I give up. My 18650 can go up to 8 amps max apparenlty, so it should support 16 amps. My module only uses 2 amps, so it should work if there was minimal wires. Hopefully, finger crossed. If this doesn’t work im cooked. But lets not think too much yk things always work out after you charge ur lithium batteries overnight cuz ur table will probably catch on fire and everything will be burnt out and u will never have to worry about it again. srry i don’t have a photo"}, {"post_id": 64716, "ts": "2026-09-09T10:34:13Z", "hours": 1.6753, "text": "Today I planned a presentation about my project for UWEN Annual General Meeting. Hopefully I can get their oppinions on how i should imrpove my solution as they are my stakehoders."}, {"post_id": 64137, "ts": "2026-09-08T10:30:30Z", "hours": 4.2833, "text": "Today I wrote a script for my video about my project so I can enter a competition. But they limit the video to be 5 minutes long, which is basicly 800 words max, but half way through i already have 1.4k words. If there is no limit i feel lik i can write a whole paper about it. But I’ll try to make it as short as possible so I don’t have to get a buzz cut and become real slim shady :D"}, {"post_id": 63449, "ts": "2026-09-07T09:35:38Z", "hours": 2.2, "text": "Today I finished all the debugging and my floating buoy is ready for testing."}, {"post_id": 62811, "ts": "2026-09-06T10:27:23Z", "hours": 10.1672, "text": "Today I did a lot of fixing in my code, but its way too buggy and I still didn’t fix all of them in 10 hours. Here are some bugs that is fixed and some changes: Dynamic memory on Arduino Nano is running out, so I tried to use the U8G2 library for my mini screen instead of the Adafruit library, but its actually using more memory and is more buggy than Adafruit. In the end I discovered that it is my string commands that I am sending to my cellular module that is gobbling up all my memory, so I used F() macro to put them into flash memory. My screen can’t connect after that change. I found out that by rendering a frame the screen library takes up 1024 bytes of dynamic memory, which is over the limit for my Arduino Nano. Arduino UART is recieving corrupted data from my cellular module. After a bit, I figured out that the built in timer of the Arduino Nano is not precise enough for 112500 baud rate, so I lowered it to 9600."}, {"post_id": 62102, "ts": "2026-09-05T10:55:10Z", "hours": 3.4672, "text": "Today I diddid aa bbibit mmomormore wwowwork oon mmy nnenew ccirccircuit anandand eeveeeveryeeveeeveryteeveeeverytheeveeeverythineeveeeveryeeveeeveryteeveeeverytheeveeeverything iis bbasicbbasiclbbasicly ddonddone aand waiwaitiwaiwaiting ffofor ffinffinaffinal cocodcode ttesttestttestittesting, aanand ii aam loloolookiloloolookinloloolooking toto fgo ffofor aa ffifiefielfield ttesttest nnenext weeweek. (ssosorrssosorry mymy kekeybkekeyboarkekeybkekeyboard iis nnot ababsabsoluababsabsoluteababsabsoluababsabsolutely worworkworkiworking sso mme isis nnot ggogoigoing tto ssay mumucmuch)"}, {"post_id": 61437, "ts": "2026-09-04T10:57:23Z", "hours": 8.5006, "text": "Today I restarted my wiring since my esp32 c3 supermini isn’t responding to my code uploads and I had to change to a Arduino Nano. And now the pH sensor doesn’t work and the organic matter sensor doesn’t work either. Hopefully i can find some magical way out tomorrow but now idk what it is because."}, {"post_id": 60730, "ts": "2026-09-03T09:10:57Z", "hours": 2.335, "text": "Another day of extreme unproductiveness. I only tried to debug my cellular module turning on and off by itself, but didn’t really solve it. Module rebooting cycle T_T :"}, {"post_id": 60117, "ts": "2026-09-02T08:56:17Z", "hours": 1.6344, "text": "Today I wished to do more but my productivity is very cooked recently. I planned to add all the final features to my code, but ended up only debugging the OLED mini display. But ok its working so I guess its alr."}, {"post_id": 59456, "ts": "2026-09-01T10:00:14Z", "hours": 1.1514, "text": "Today I did a bit more work on the buttons and screen."}, {"post_id": 58751, "ts": "2026-08-31T09:51:06Z", "hours": 2.6522, "text": "I got a bucket and put some pollutants in there (dirt and DIY-ed dissolved organic matter), to test the sensors (that detects pollution by seeing how much light it absorbs, UV for organic matter and normal light for turbidity) and getting a threshold value that will define what is polluted water and what is not for my water quality buoy. However, I made the dissolved organic matter solution a while ago, and it doesn’t seem to absorb UV anymore. Apparently its because the bacteria ate all the organic matter, or it precipitated out as large clumped molecules. But I can’t be bothered to make some fresh solution so I just made up some values for the organic matter sensor (very scientific approach :D)."}, {"post_id": 57986, "ts": "2026-08-30T10:07:16Z", "hours": 12.6839, "text": "Today I sat in my desk all day at my project. I made all the sensor connection work, power system, soldering stuff (and getting burnt 99999 times), drilling holes, epoxy resin -ing (they should invent a word for this), and coding. It feels like its going to work, but I still need to wait to tomorrow to do a few final changes to my code and test it."}, {"post_id": 56557, "ts": "2026-08-28T11:12:23Z", "hours": 3.3183, "text": "Today I tried to figure out which of my components have been fried by my dc booster accident. Luckily, its just the photodiode (OPT101) that i use to test turbidity. I didn’t believe that it was broken even though it outputted strait 0v with light and without light, since it apparenlty can handle up to 36v. But after lots of testing i think it is indeed broken. I soldered on a new one, but i soldered the pin headers teh wrong way around (this is like the 1 billionth time i did this wrong) so I tried to take the headers off. But i didn’t have any solder wick or anything, so i tried to pull the headers off (which is very very stupid), and i did pull the headers off… along with a big chunk of the PCB. So yeah, no more photodiodes. But fortunately I do have some LDRs and ill use tehm, hope its accurate enough."}, {"post_id": 56388, "ts": "2026-08-28T04:25:21Z", "hours": 3.9839, "text": "I tried to test my circuit that i put inside the casing, but there was some problems with the step up booster to make the 4v from my 2 parallel18650 into 5v. However, two of my step ups randomly jump to 20v for a while and then will jump back to exactly 5v, and after a while 20v again. I tried another step up, and that one won’t go down below 10v. I thought that its probably my circuit drawing too less power causing the booster to be unstable, so i added a 470 ohm resistor to the outputs. It still didn’t work after a while. I was very confused and forgot to pull out the resistor out of the malfunctioning booster that was at 20v…. the parallel 18650s made it even worse. So then I smell something burning. I didn’t know that it was the resistor burning, so I just took the resistor off with my fingers, and I got burnt. D: But later I found out that its actually so dumb. I wasn’t sure if my step ups were working at first so I didn’t fully secure the battery wires into the terminals, so in case something went wrong I can just immediately pull the power source out. However, the bad connection of the wires with the terminal made the step up really unstable, causing it to jump to random high voltages. So I guess by being more carefull I actually ended up worse…..? Ok I see. :D Also most of my circuit was connected to the step up (thats even dumber), and the 20v fried my conductivity module, and I think maybe my sensors too but I still need to check (fingers crossed). T_T very cooked"}, {"post_id": 54941, "ts": "2026-08-26T11:09:43Z", "hours": 2.4514, "text": "I put most of my electronics into my buoy casing. The wires are totally very neat and I totally don’t need a flashlight and tweezers to move teh wires. (its way worse than it looks) Theres still a bunch of parts I need to add. I think the buoy is going to sink because the wires weight too much :P. And i feel like my wires are made out of resistors a whole volt dissapeared in a single section of wire."}, {"post_id": 54365, "ts": "2026-08-25T10:14:25Z", "hours": 1.7508, "text": "I printed the parts for my buoy, some needs reprinting. I installed some working parts, and glued some sensor windows with ab epoxy for waterproof. Theres still lots of work to do!"}, {"post_id": 54029, "ts": "2026-08-24T19:38:16Z", "hours": 5.0172, "text": "I emailed a few councils in my country for some feedback onto my project, since they are part of the stakeholders. They said that I should add confidence level for GPS, CSV file save, adjustable measurement intervals, and official guildeline comparism. I added savable CSV for the data and adjustable intervals, but I didn’t do confidence level for GPS cuz my GPS module doesn’t measure carrier to noise ratio. I didn’t do the official guildeline comparism because I made most of the sensors and the only way to convert the data from the sensors to official units is to use calibration sollutions, which is kinda expensive."}, {"post_id": 52212, "ts": "2026-08-22T09:43:18Z", "hours": 6.2258, "text": "Today I started making the 3D model for the buoy itself. I finished most of it, including the top controls, GPS solar panel, and the space for the electronics."}, {"post_id": 50812, "ts": "2026-08-20T07:15:18Z", "hours": 3.2072, "text": "After more than a total of 20 hours of coding, debugging, restarting, crashes…. The server code is working. :D"}, {"post_id": 50538, "ts": "2026-08-19T18:43:10Z", "hours": 3.0325, "text": "I FINALLY debugged the server analysis system. I made a new more organised and simpified code since my original one is way to over OVER complicated."}, {"post_id": 49853, "ts": "2026-08-18T20:01:59Z", "hours": 1.4833, "text": "I ran the buoy code and debugged it. There was a few code mistakes and a few power source problems, but it was alright. However, the server code on the right seems very buggy, millions of errors. Hopefully its not that bad when I test that later."}, {"post_id": 49470, "ts": "2026-08-18T10:17:32Z", "hours": 3.4214, "text": "I debugged the extremely buggy server data analysis code, with help from deepseek because the arrays are getting a bit messy."}, {"post_id": 48749, "ts": "2026-08-17T08:53:48Z", "hours": 3.2239, "text": "I added another function to my analysis of the data, which can combine the individual sources detected from each of the different water quality sensors into real sources that may be the source for many of the individual sources."}, {"post_id": 48434, "ts": "2026-08-16T19:39:36Z", "hours": 0.5733, "text": "My code is going to be really buggy, so I added some debugging print() for easier debugging to the local server."}, {"post_id": 47999, "ts": "2026-08-16T08:50:29Z", "hours": 2.4289, "text": "I coded most of the analysis programme for the reciever. It can calculate how far down a pollution source affect from GPS data from my buoy, identify turbidity and dissolved organic matter problems, and respond to sudden change in pH or conductivity."}, {"post_id": 47868, "ts": "2026-08-16T03:43:31Z", "hours": 5.3475, "text": "Turns out i forgot to do a huge chunk of the reciever code, which is to analyse and display the data. I finished most, just a bit left!"}, {"post_id": 47405, "ts": "2026-08-15T10:01:26Z", "hours": 1.8936, "text": "Water buoy data sending and reciever server code. Just finishing on the finshing of from what I did before."}]...
|
Title: Project FlowMark by @The_Hedgehog | Stardan Title: Project FlowMark by @The_Hedgehog | Stardance
Devlogs:
Water buoy data sending and reciever server code. Just finishing on the finshing of from what I did before.
Turns out i forgot to do a huge chunk of the reciever code, which is to analyse and display the data. I finished most, just a bit left!
I coded most of the analysis programme for the reciever. It can calculate how far down a pollution source affect from GPS data from my buoy, identify turbidity and dissolved organic matter problems, and respond to sudden change in pH or conductivity.
My code is going to be really buggy, so I added some debugging print() for easier debugging to the local server.
I added another function to my analysis of the data, which can combine the individual sources detected from each of the different water quality sensors into real sources that may be the source for many of the individual sources.
I debugged the extremely buggy server data analysis code, with help from deepseek because the arrays are getting a bit messy.
I ran the buoy code and debugged it. There was a few code mistakes and a few power source problems, but it was alright. However, the server code on the right seems very buggy, millions of errors. Hopefully its not that bad when I test that later.
I FINALLY debugged the server analysis system. I made a new more organised and simpified code since my original one is way to over OVER complicated.
After more than a total of 20 hours of coding, debugging, restarting, crashes…. The server code is working. :D
Today I started making the 3D model for the buoy itself. I finished most of it, including the top controls, GPS solar panel, and the space for the electronics.
I emailed a few councils in my country for some feedback onto my project, since they are part of the stakeholders. They said that I should add confidence level for GPS, CSV file save, adjustable measurement intervals, and official guildeline comparism. I added savable CSV for the data and adjustable intervals, but I didn’t do confidence level for GPS cuz my GPS module doesn’t measure carrier to noise ratio. I didn’t do the official guildeline comparism because I made most of the sensors and the only way to convert the data from the sensors to official units is to use calibration sollutions, which is kinda expensive.
I printed the parts for my buoy, some needs reprinting. I installed some working parts, and glued some sensor windows with ab epoxy for waterproof. Theres still lots of work to do!
I put most of my electronics into my buoy casing. The wires are totally very neat and I totally don’t need a flashlight and tweezers to move teh wires. (its way worse than it looks) Theres still a bunch of parts I need to add. I think the buoy is going to sink because the wires weight too much :P. And i feel like my wires are made out of resistors a whole volt dissapeared in a single section of wire.
I tried to test my circuit that i put inside the casing, but there was some problems with the step up booster to make the 4v from my 2 parallel18650 into 5v. However, two of my step ups randomly jump to 20v for a while and then will jump back to exactly 5v, and after a while 20v again. I tried another step up, and that one won’t go down below 10v. I thought that its probably my circuit drawing too less power causing the booster to be unstable, so i added a 470 ohm resistor to the outputs. It still didn’t work after a while. I was very confused and forgot to pull out the resistor out of the malfunctioning booster that was at 20v…. the parallel 18650s made it even worse. So then I smell something burning. I didn’t know that it was the resistor burning, so I just took the resistor off with my fingers, and I got burnt. D: But later I found out that its actually so dumb. I wasn’t sure if my step ups were working at first so I didn’t fully secure the battery wires into the terminals, so in case something went wrong I can just immediately pull the power source out. However, the bad connection of the wires with the terminal made the step up really unstable, causing it to jump to random high voltages. So I guess by being more carefull I actually ended up worse…..? Ok I see. :D Also most of my circuit was connected to the step up (thats even dumber), and the 20v fried my conductivity module, and I think maybe my sensors too but I still need to check (fingers crossed). T_T very cooked
Today I tried to figure out which of my components have been fried by my dc booster accident. Luckily, its just the photodiode (OPT101) that i use to test turbidity. I didn’t believe that it was broken even though it outputted strait 0v with light and without light, since it apparenlty can handle up to 36v. But after lots of testing i think it is indeed broken. I soldered on a new one, but i soldered the pin headers teh wrong way around (this is like the 1 billionth time i did this wrong) so I tried to take the headers off. But i didn’t have any solder wick or anything, so i tried to pull the headers off (which is very very stupid), and i did pull the headers off… along with a big chunk of the PCB. So yeah, no more photodiodes. But fortunately I do have some LDRs and ill use tehm, hope its accurate enough.
Today I sat in my desk all day at my project. I made all the sensor connection work, power system, soldering stuff (and getting burnt 99999 times), drilling holes, epoxy resin -ing (they should invent a word for this), and coding. It feels like its going to work, but I still need to wait to tomorrow to do a few final changes to my code and test it.
I got a bucket and put some pollutants in there (dirt and DIY-ed dissolved organic matter), to test the sensors (that detects pollution by seeing how much light it absorbs, UV for organic matter and normal light for turbidity) and getting a threshold value that will define what is polluted water and what is not for my water quality buoy. However, I made the dissolved organic matter solution a while ago, and it doesn’t seem to absorb UV anymore. Apparently its because the bacteria ate all the organic matter, or it precipitated out as large clumped molecules. But I can’t be bothered to make some fresh solution so I just made up some values for the organic matter sensor (very scientific approach :D).
Today I did a bit more work on the buttons and screen.
Today I wished to do more but my productivity is very cooked recently. I planned to add all the final features to my code, but ended up only debugging the OLED mini display. But ok its working so I guess its alr.
Another day of extreme unproductiveness. I only tried to debug my cellular module turning on and off by itself, but didn’t really solve it. Module rebooting cycle T_T :
Today I restarted my wiring since my esp32 c3 supermini isn’t responding to my code uploads and I had to change to a Arduino Nano. And now the pH sensor doesn’t work and the organic matter sensor doesn’t work either. Hopefully i can find some magical way out tomorrow but now idk what it is because.
Today I diddid aa bbibit mmomormore wwowwork oon mmy nnenew ccirccircuit anandand eeveeeveryeeveeeveryteeveeeverytheeveeeverythineeveeeveryeeveeeveryteeveeeverytheeveeeverything iis bbasicbbasiclbbasicly ddonddone aand waiwaitiwaiwaiting ffofor ffinffinaffinal cocodcode ttesttestttestittesting, aanand ii aam loloolookiloloolookinloloolooking toto fgo ffofor aa ffifiefielfield ttesttest nnenext weeweek. (ssosorrssosorry mymy kekeybkekeyboarkekeybkekeyboard iis nnot ababsabsoluababsabsoluteababsabsoluababsabsolutely worworkworkiworking sso mme isis nnot ggogoigoing tto ssay mumucmuch)
Today I did a lot of fixing in my code, but its way too buggy and I still didn’t fix all of them in 10 hours. Here are some bugs that is fixed and some changes: Dynamic memory on Arduino Nano is running out, so I tried to use the U8G2 library for my mini screen instead of the Adafruit library, but its actually using more memory and is more buggy than Adafruit. In the end I discovered that it is my string commands that I am sending to my cellular module that is gobbling up all my memory, so I used F() macro to put them into flash memory. My screen can’t connect after that change. I found out that by rendering a frame the screen library takes up 1024 bytes of dynamic memory, which is over the limit for my Arduino Nano. Arduino UART is recieving corrupted data from my cellular module. After a bit, I figured out that the built in timer of the Arduino Nano is not precise enough for 112500 baud rate, so I lowered it to 9600.
Today I finished all the debugging and my floating buoy is ready for testing.
Today I wrote a script for my video about my project so I can enter a competition. But they limit the video to be 5 minutes long, which is basicly 800 words max, but half way through i already have 1.4k words. If there is no limit i feel lik i can write a whole paper about it. But I’ll try to make it as short as possible so I don’t have to get a buzz cut and become real slim shady :D
Today I planned a presentation about my project for UWEN Annual General Meeting. Hopefully I can get their oppinions on how i should imrpove my solution as they are my stakehoders.
Today I tried to power my cellular module with my two 18650 in parallel. It kinda works for a while but then the voltage dips and the module turns itself off. Its most likely the thin wires, and I optimised it as much as I can, but the same thing happens. I will charge my batteries up again and if it still dont’ work I will just skip my MOSFET circuit that turns the module on and off, as this thing still has a bit of thin wires. If it STILL dont’ work I give up. My 18650 can go up to 8 amps max apparenlty, so it should support 16 amps. My module only uses 2 amps, so it should work if there was minimal wires. Hopefully, finger crossed. If this doesn’t work im cooked. But lets not think too much yk things always work out after you charge ur lithium batteries overnight cuz ur table will probably catch on fire and everything will be burnt out and u will never have to worry about it again. srry i don’t have a photo
Today I finally made my cellular module work, as before it always shut down due to thin wires burning up too much voltage. My free floating buoy is ready for testing!
Today I almsot finished the slides for my presentation for UWEN next week, so I can go there and get some feedback.
Ships:
I made a buoy that can float freely down a river. It has four sensors, pH, conductivity, dissolved organic matter, and turbidity. It constantly uses these sensors to take measurements and sends it to a locally hosted Python Flask server tunneled using Ngrok. After the buoy is collected from the water, the server will analyse the data and find out where the water quality started to worsen, therefore finding out where riverine polution might be. Although the project wasn’t very complicated, I faced many many problems. The most memorable and most fustrating ones: I use a step up module to turn the 4v from my 18650 to 5v for my ESP32 C3 Supermini. But the step up often randomly output over 20v, though it is set for 5v. I later found out that its because a loose connection between my battery and the step up, but the voltage spikes has badly burnt many things in my circuit. The ESP32 C3 Supermini suddenly cannot connect to my computer. I tried holding down boot button, boot and reset, redownload a driver, and trying all the ports on my computer and in Arduino IDE. But it just won’t work. So I changed to a Arduino Nano. But that just made things worse. The Arduino Nano successfully connected to my computer, but it often corrupts recieved UART signals from my cellular module. Later I found out that its because the Arduino Nano’s clock is a bit off for 112500 baud. This made things more complicated because I need to start the UART communication between the Nano and the cellular module at 112500 (since my cellular module is default 112500 when start up), then request the cellular module to turn down to 9600, and then change the Nano UART back to 9600. It did finally work tho. I guess this is the worst nightmare in my project. My project uses a pair of 18650 in parallel, as it can have more power to sustain my buoy for longer. But the cellular module often shut down right after it turns on. It turns out that the celular module can pull up to 2 amps when connecting to the cellular tower and sending messages, which is causing the voltage drop. However, this was weird because the two 18650 cells I had is the Samsung 25R, which has a max discharge of 20 amps. Parallel means that the max discharge become 40 amps, which is wayyyyyyy more than the 2 amps required. So the problem must not be the batteries. Or is it? I suspect that the batteries are fake. They weigh pretty normal, being 44 grams. I checked the imprints on the wrapping, and it did have a legitemate manufacture date code that says someday in 2017 (I forgot which day it was, but it was 2017). And I also took off the battery wrapping, and it did had Samsung factory imprints on the metal. So the battery is good, the cellular module can only take up to 2 amps….. then the problem must be between the cellular module and the battery! And it was. It was the thin jumper wires and breadboard that decreased the voltage when the current increased. Shorter thicker wires solved it. There was actually much more issues, but these are the most memorable ones for me. I am glad that my project turns out to be working, becuase i genuinely thought that it would never work when making it....
|
1793004507.518697
|
1793090907.518697
|
|
6534
|
Math Suite by @R10 | Stardance
|
R10
|
0
|
105.42
|
0
|
[]
|
[{"post_id": 58033, "ts": "202 [{"post_id": 58033, "ts": "2026-08-30T11:44:29Z", "hours": 7.6675, "text": "DEVLOG #21 Completed the CLI tool and created binaries for windows and linux using pyinstaller. Also completed the full Guide page on the website with all the relevant rules, syntax and limitations listed cleanly."}, {"post_id": 54909, "ts": "2026-08-26T04:03:17Z", "hours": 1.2047, "text": "DEVLOG #20 Completed and wired Unparser TRY NEW UPDATE I completed the unparser now with the precedence based approach and I can’t believe how much simpler it is and how bad my initial approach was. The thing that makes it work is the new needs_paren function which basically does all the precedence based logic of telling if the child needs parenthesis or not. Basically if the child’s precedence is lower than the parent op then we need a parenthesis. For example: if the child is a + node and the parent is a * node then we would need parenthesis on the child. For example: (x+1) * 3 -> x+1 needed parenthesis. The main part that made me think a bit was the case when precedence of the child and parent is equal. There are basically 3 cases here: When op is + or * , the child never needs parenthesis. When op is - or / , the child only need parenthesis if it is on the right side. For example: precedence of + == - , a + b - c -> a+b is on the left side and hence does not needs parenthesis. Whereas, c - (a+b) -> a+b on the right side needs parenthesis because this basically means c - a - b and not c - a + b . Hence, parenthesis is required. When op is ^ , parenthesis is only required when the child is on the left and not when it is on the right. For example: a^b^c does not need parenthesis (even though it could be written as a^(b^c) ) but, (a^b)^c needs parenthesis because this means a^(b*c) as the powers multiply. I have also wired in the unparser function to derivative and simplify too so now the result is an expression instead of a tuple. Now I will update my README.md and explain the working of the unparser and then I will work on adding the guide page to my website."}, {"post_id": 54516, "ts": "2026-08-25T15:24:49Z", "hours": 3.9794, "text": "DEVLOG #19 Another Setback I was working on the unparse function today. Basically the idea was simply to recurse through the tree and form the expression as a string. Now, the hard part in this was to decide when to apply parenthesis. Basically, we have to apply parenthesis to any child of the function which has a lower precedence then the current parent op. I did not have this idea as well set in my mind when i was making this function and I just wasted 4 hours today trying to stack up elif cases with or conditions to try to cover every shape. Basically, I was thinking that for * / / , there are only 4 base cases: both children need parenthesis left needs parenthesis right needs parenthesis none need parenthesis I took that as a starting point and then i started to think of cases which would satisfy that and that caused me to build up this or-or-or jargon. I am really pissed. Now I will change my direction and move onto a precedence based approach which checks if the precedence of the child is lesser than the parent op, if yes then parenthesize it and if no then check if precedence is equal, if it is then check for associativity. That is the plan and I hope I don’t mess up this time."}, {"post_id": 53795, "ts": "2026-08-24T14:32:20Z", "hours": 4.6131, "text": "DEVLOG #18 LIVE PROJECT I have finally deployed the Version-1 of the project on vercel, check it out at the link above. I also completed the README for my repo explaining all the features and limitations of the project. Now I will be working on making an unparser to show the users a clean expressions as a result from the calculator instead of AST nodes and I will also add a guide page on the website for the syntax rules and general guide."}, {"post_id": 53022, "ts": "2026-08-23T12:29:17Z", "hours": 6.5536, "text": "DEVLOG #17 Completed Styling (would appreciate feedback) Features: AST generator AST visualizer (downloadable SVG trees) Domain calculator Range Calculator Derivative calculator Simplification Next steps: AST back to expression generator because right now all the calculators give the result in terms of AST nodes so i need a reverse-parser which I think would be easy. Making a simpler bare bones CLI tool for simpler People. adding a guide page to the website explaining all the limitations and syntax of the calculator. hosting on my own domain? That is all that I can think for now. Right now I have not hosted the website because I am thinking of adding a few more features like user changeable SVG node and line colors, etc."}, {"post_id": 51764, "ts": "2026-08-21T16:32:30Z", "hours": 7.3219, "text": "DEVLOG #16 More PROGRESS! completed range.py tested edge cases with some pretty nasty ones and have decided to leave some limitations like not supporting gif/frac/sec/tan… functions because of their nature. General Debugging created all the flask endpoints along with the basic HTML layout of the website and wiring in the JS. Website is tested and all endpoints are working Now, I will focus on adding some styling to the website and also making the user experience better."}, {"post_id": 50948, "ts": "2026-08-20T12:44:34Z", "hours": 7.7231, "text": "DEVLOG #15 Real PROGRESS! Completed the full differentiation pipeline which is working completely now with all edge cases (that I have tested) handled. converted simplify to a standalone file as I noticed that simplify could be used as a general simplification pipeline for ALL generated nodes in my maths suite. Created pow_to_div function in simplify to turn negative exponents into division nodes to make the simplification pipeline truly generalized because none of my other algorithms expect a negative exponent. A LOT of debugging in domain.py and testing some edge cases. Adding support for multiple exclusions instead of single in normalize_domain . Earlier: (-∞, -2) ∪ (-2, 2) ∪ (2, ∞) Now: R-{-2, 2} which is a much cleaner solution Now I am working on completing range.py and then finally making the website for the full maths suite. I am a bit confused. I am not able choose between flask and FastAPI. If you have read all this then would you also mind sharing your opinion on what should I use in the comments?"}, {"post_id": 48137, "ts": "2026-08-16T13:02:18Z", "hours": 7.85, "text": "DEVLOG #14 Completed the full simplify_initial pipeline. Handled cases with 0 and 1 and traced a full long recursion by hand to better understand the pattern and make iterative debugging faster. Also handled negative node by simplifying the ('*', '-1', right) node formed so that any coefficients collapse cleanly and the term can form correctly with a negative coefficient. EXAMPLE:- Earlier: x - 3x -> terms = [(1.0, 'x', 1.0), (-1.0, ('*', '3', 'x'), 1.0)] Now: x - 3x -> terms = [(1.0, 'x', 1.0), (-3.0, 'x', 1.0)] Therefore, now merging terms will result in ('*', '-2', 'x') I pasted my code into claude and asked it to generate me some test cases which it believes would fail and now I am working on debugging them with a mix of hand tracing recursion and simple fixes so the pipeline is almost at its end (I hope)."}, {"post_id": 45545, "ts": "2026-08-12T03:20:05Z", "hours": 7.77, "text": "DEVLOG #13 I have completed the basic simplification functions now but, it is not working perfectly and there are still some changes to be made. for example, handling cases where it is multiplied by 0, or when 0 is added, or it is multiplied by 1, etc. so I think it requires a bit more of iterative debugging to catch all of the edge cases. I have formalized the design of simplification into: Flatten -> form_term -> merge_terms -> form_node -> rebuild which is much better then the previous logic that I had where I was adding more edge cases for handling each case. Right now I will be testing the full recursion for a test case to check where it goes wrong right now in the pipeline to fix it."}, {"post_id": 42398, "ts": "2026-08-07T02:47:07Z", "hours": 8.9103, "text": "STUCK So basically, since my last devlog, the main feature of the new derivative calculator that I had proudly announced is now coming to bite me. The simplification is so tough. Let me explain you all the turn of events. (Simplification is still not complete) basically, my initial idea of simplification was just removing all the temporary zeros and ones that were generated by the derivative itself. Then I thought of increasing the initial scope to support some other simplifications like (‘ ’, ‘2’, (’ ’, ‘2’, ‘x’)) should be solved to (‘ ’, ‘4’, ‘x’). I managed to achieve this simplification too but, I found out there are a lot more simplification cases that I need to handle after we get the derivative. for example: x - 3x, which should be simplified to -2x. For that I had to build an approach which would take the coefficient and base then operate on the coefficients for the same bases according to the operator. Therefore, for x the coeff is 1 and then for 3x the coeff is 3 but that is incorrect. In the case of x-3x, the coefficients should be 1 and -3 so that when i add them i get -2 as the final coefficient for x. To do that, I had to switch all binary subtraction expression and turn them into additive unary negative for op = ‘+’ so that x - 3x turns into x + (-3x). Now, all this actually worked but the main problem was that now the flattened list looks like [‘x’, (’ ’, ‘-1’, (‘ ’, ‘3’, ‘x’))] which means I cannot reliably extract the coefficients now. I first have to handle the recursive case of flattening the node again, turning (’ ’, ‘-1’, (‘ ’, ‘3’, ‘x’)) to the flattened version [‘-1’, ‘3’, ‘x’] and then i would have to run it back through combine where it would be formed as calc = -3 and symbols = ‘x’ and then rebuild it as the node (’ ’, ‘-3’, ‘x’). Only after that can i actually extract the coefficients and compare the bases of the two expressions which would be 1 and -3 and calculate them according to the op => ‘+’ to finally give -2 as calc and ‘x’ as symbols and then rebuild that again into (‘ ’, ‘-2’, ‘x’) to solve it. Now this was just one case for one operator but i need to handle both ‘+’ and ’ ’ as the both have associativity and there are other cases for other ops too like x^2/x should just simplify to x. I have already added so much code that I myself feel like the approach is very wrong and the more I build the more edge cases I am adding because right now the amount of if-else handling for specific cases is crazy so I really think that I need to reconsider my approach for simplification. The derivative calculator is taking too much time considering it is an intermediate step but I think it would be worth it because this simplification step is something that I have never done before so I would be learning something anyway."}, {"post_id": 37427, "ts": "2026-07-30T04:49:03Z", "hours": 8.0483, "text": "Derivative For finding the range, I am opting for method of differentiation to check intervals. hence, I have made derivative.py for differentiation. This is my second derivative calculator. The first one that I built was made completely using string slicing and weird string manipulation and pretty biased logic where everything was stored in the form of a dictionary. To be honest, I was pretty proud of that calculator because I was able to make it just using the knowledge I had, and recursion is not innate (I think) and I was still able to do it so I am proud of it. But, it was no doubt pretty inefficient with a lot of edge cases. Therefore, this time i am making a better calculator using my new AST representation and A LOT more recursion. This calculator will process more functions and it will be able to simplify the derivative too, for example: derivative of 2x^2 will not be displayed as 2*2x, rather it will be correctly displayed as 4x."}, {"post_id": 33852, "ts": "2026-07-24T03:07:49Z", "hours": 6.1169, "text": "Devlog #10 Completed domain.py finished coding domain.py and tested about 20 test-cases on it. Completed debugging to finally finish domain calculation and start with Range. I do not know what else to tell you all as it has been a few days of coding and debugging with different bugs surfacing like incorrect handling of undefined functions, normalizing output, handling union cases correctly, etc."}, {"post_id": 32213, "ts": "2026-07-21T07:27:55Z", "hours": 5.6939, "text": "Union and Intersection of intervals I have made the intersection function which takes intervals and unions them together. I am now working on the union function. I initially used recursion to do the job but that was incorrect that the better method was just to sort the intervals list and then use a simple loop to evaluate the union. Here is the issue i was facing: [[A, B, C, D], E] AUE-> False, BUE-> False, CUE-> True => [F, A, B, D] union [F, A, B, D]-> FUA-> False => [[F,A], B, D] again [F,A], B => FUB-> False, BUA-> False => [F, A, B] => union this list now => FUA-> False => [[F,A], B] then again [F,A], B => FUB-> False, BUA-> False => [F, A, B] => FUA-> False => [[F,A], B] this goes on and on infinitely This is a problem of infinite recursion"}, {"post_id": 30591, "ts": "2026-07-18T09:17:11Z", "hours": 4.9469, "text": "It has been a tough journey If you read my previous devlog, it almost feels like i was foreshadowing what was about to happen to me. While making the solve_node function which would solve the inequality for x, i got lost in the mess of symbolic mathematics and started handling cases with fallbacks upon fallbacks. It has really a hot mess, I got to find out that there can be many types of questions and to solve every type of domain question, I would need fallback logic for every type of question which would mean I would have to encompass all the techniques in domain finding into the file and manage the interaction of the techniques and orchestrate them at a high level and basically making my own sympy (which took decades to build). I even thought of quitting a few times and the project was basically at a halt for 1-2 days. I then decided to solve a simple domain question by hand to check what really are the steps of finding the domain of a function. I found out that my logic up until making the constraints was fine. The next steps were finding critical points for example: (x-2)(x+3)>0 would have critical points 2 and -3 (they are just the points where the function is zero). Now, I also know that critical points also occur when the sign of the function changes or when its nature changes (going from defined to undefined and vice-versa) so instead of making a symbolic critical point finding function I thought of a more brute force method. If I have a number line (range of numbers) and i simply walk through them one by one, noting sign change between 2 numbers as a sign “there is a critical point here” and then use another function to basically go into each of those marked intervals and continuously half the interval (think of it as taking an interval and then zooming into the interval until you find the critical point) until about 9 decimal places (could be anything, it is just the amount of accuracy), you would get the critical point pretty accurately without having to solve anything using logic or symbolically, just substitute values of x. After finding the critical points, turning it into domain is as simple as just substituting points and see if the inequality holds."}, {"post_id": 28299, "ts": "2026-07-14T13:49:18Z", "hours": 2.7275, "text": "Domain Calculation Started the domain calculation file (domain.py) and made the function get_constraints() that recurses through the tree to look for domain restricting operators like /, sqrt, log, arcsin, etc. into a list. next steps are to solve each of the generated constraints (inequalities) and then combine them to get the domain for x (or any variable). Currently working on trying to solve the inequalities but it is proving to be pretty difficult so it could take longer than usual."}, {"post_id": 27119, "ts": "2026-07-12T12:03:05Z", "hours": 0.3206, "text": "AST Visualizer (continued) Case-2 If the node is not a leaf (i.e. not a string) we will again check for 2 cases. the node can either have 1 child or 2 children. If there are 2 children then we have to make 2 recursive calls but if we have a single child then only one and the other stuff is pretty similar so I will only explain the case when there are 2 children. first of all, we unpack the node to get op, left and right. Now we call assign_positions with depth+1 (to effectively track each level we go down), on left and right and extract: x-position of children, id of children and the parameters that get updated (id_count and leaf_count). next, we used children’s x-position, average it to get the op’s x-position. We make the tree: tree[op_id] = {'label': op, 'x': op_x, 'depth': depth, 'children': [l_id, r_id]} . Now we increase the id_count by 1 but not the leaf_count as we have not encountered a leaf (I had made a mistake here and increased leaf_count in the case where the node is not a leaf because I had named the variable as x_position earlier and thought that it must increment everywhere but forgot that we are averaging the children’s x-position to get op’s x-position so i do not need to increment it, which is why I have cleared this up). Now we return the same stuff: op_id, id_count, op_x, leaf_count, tree. Rendering Tree The actual tree generation is simply looping through the dictionary. The important function is converting x_position and depth values that are simple integers into actual pixel positions to actually position the circles in the correct spot which is done by pixel_x = margin+x*x_spacing and pixel_y = margin+depth*y_spacing where margin, x_spacing and y_spacing are all hyper-parameters. The next function is draw_nodes which simply loops though the values of tree dictionary gets the x and depth for each node, converts them to actual coordinated using get_pixel_coords and then creates the svg line: '<circle cx=\"{x}\" cy=\"{y}\" r=\"25\" fill=\"white\" stroke=\"black\" /> <text x=\"{x}\" y=\"{y}\" text-anchor=\"middle\" dominant-baseline=\"middle\">{i['label']}</text>' for each node and its text. The other is draw_lines. It takes all the parent nodes and gets their x and y value as pixel coordinates. Then, it gets the children of the node and for each child’s id, the function gets the child by its id, then gets the x and y coordinates of the child as pixel coordinates and then draws the line as per this syntax: f'<line x1=\"{x1}\" y1=\"{y1}\" x2=\"{x2}\" y2=\"{y2}\" stroke=\"white\" />' Finally we have the render_expression function which wraps everything into a single sequence of operations and creates the final svg code: f'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"850\" height=\"650\"> {lines} {nodes} </svg>' and created an svg file to view the final tree."}, {"post_id": 27067, "ts": "2026-07-12T09:05:33Z", "hours": 3.9078, "text": "AST Visualizer After completing my tokenizer and parser with a few fixes, I wanted to move straight onto building the actual domain and range logic and setting up all the constraints, but instead, I had another idea. Whenever I saw the output of my parser, it just seemed a bit meh . The output was just a nested tuple and it was not looking like what I had built was a tree. So, as a side quest, I built an SVG AST visualizer that takes the tuple and build its tree and it is SVG and not matplotlib so that if I ever decide to turn this program into a website, I can simply plug in this code and get the output straight in a web page. How it works: For the people curious as to how it works, I am sorry if my explanation does not make sense because even I do not understand it very well (I am pretty bad at recursion). basically, the main function that lets me plot these nodes in a 2D space is assign_positions. If we do not focus on recursion yet, the basic idea of this function is that there are 2 types of node: leaf nodes and internal nodes . Leaf nodes are the nodes which do not have any children and terminate the branch i.e. are terminal . whereas, internal nodes have children and branch out further to extend the tree i.e. are non-terminal . The basic hypothesis was that if there are two leaf nodes, and I assign them an x-position of 0 and 1, their parent node should be at a position which is the mid point (or average) of its children. Which means, the parent node of two leaf nodes (or internal nodes) at x-position 0 and 1 would lie at x-position 0.5 (avg of 0 and 1). now for the y-position, I have used depth as the name where the idea was simply that with every new node, the depth should increase by 1. Now we come to recursion and how I generalized this position idea to any possible tuple. The basic things that the assign_positions function takes are: node-> Current node depth-> Current depth/ y-position id_count-> The ID assigned to the node leaf_count-> Basically the x-position of the leaves tree-> Current tree dictionary There are 2 cases, the node can either be a leaf or an internal node. If the node is a leaf node, then we simple make the tree: tree[str_id] = {'label': node, 'x': str_x, 'depth': depth} . we increase leaf_count by 1 (because if the x-position assigned to this node was 0 then the next leaf node should have it as 1) and we increase id_count by 1. This case returns the x-position assigned to this node-> str_x, the id assigned to this node-> str_id, the current id_count, the current leaf_count and the current tree. These specific constraints are returned because If a parent had done a recursive call and the node was a leaf node then the parent would require: the child’s x position to average left and right positions to set its own position. the child’s id to keep track of it in its own dictionary. the current id_count and leaf_count so that an assigned number is not reassigned to another node by mistake in a recursive call. Case-2 and tree rendering covered in next devlog"}, {"post_id": 26425, "ts": "2026-07-11T06:35:09Z", "hours": 1.6078, "text": "Debugging Day fixed unary negative operation on a function like -sqrt in the tokenizer. added support for implicit multiplication in the tokenizer (right now only valid for alphabets after numbers like 3x, 25x, etc. and not for alphabet after alphabet like xsin(x), xlog(x), etc.) fixed the decimal point collection in the tokenizer due to the failed test case: -.5 Added support for exponents by adding parse_pow() . initially i had simply copied the structure of parse_add and parse_mul and ran the test case but i found out that the result was wrong. My current parsing algorithm has natural left associativity, which is required for other operators but, is wrong for power. Because, 2^3^2 should result in 2^(3^4) and not (2^3)^4, which means i needed right associativity. For getting right associativity, i had to make it such that the right term of the node was recursively calling parse_pow(), so that everything after it would get parsed first which would give us right associativity."}, {"post_id": 25763, "ts": "2026-07-10T06:37:12Z", "hours": 5.1942, "text": "Parser Testing I spent about 4 hours testing and debugging the recursive decent parsing algorithm, trying to understand the flow by writing each and every step. Here are my test cases. Test case-1 exp = 2+3*4 tokens = ['2', '+', '3', '*', '4'] expected result = ('+', 2, ('*', 3, 4)) This test case was used so that i can better understand parse_add and parse_mul along with the main parse_atom. Reached the correct answer. Found a bug in approach: I was not handling the case when pos was out of index ideally. Researched a bit on RDP and found out there is a basic template used in RDP which is while pos < len(tokens) ... and thus used this refined knowledge in my successive attempts. Test case-2 exp = 2+3+4+5 tokens = ['2', '+', '3', '+', '4', '+', '5'] expected result = ('+', ('+', ('+', 2, 3), 4), 5) This specific test case defines why a while loop is important as it includes accumulation of same operator. I wanted to work through this by hand as I was really confused why we need a while loop instead of a simple if-else check whether the pos is out of range or not but the answer became clean when i worked through it. Reached the correct answer. Test case-3 exp = (2+3)*4+1 tokens = ['(', '2', '+', '3', ')', '*', '4', '+', '1'] expected result = ('+', ('*', ('+', 2, 3), 4), 1) I used this test case as it introduces parenthesis into the parsing algorithm which is a fundamental feature. correctly worked through the parsing and reached the correct answer. Parser I also completed the v1 of the parser in just 20 minutes. It is pretty hilarious that it took me 4 hours just to understand RDP but 20 minutes to code it. But, I believe those were 4 hours well spend because earlier, I found RDP to be mind breaking, but now I understand it so well that I think I can teach it even to a 12 year old."}, {"post_id": 24691, "ts": "2026-07-08T13:28:05Z", "hours": 1.3383, "text": "Tokenizer progress: 1. Added decimal point support: Failed attempt : I initially tried to detect . from inside the .isdigit if-elif loop like detecting a continuation of digits but failed on case \"12.34\" → ['1234'] and then found the simpler solution. Added elif exp[i] == \".\": num.append(exp[i]) as its own top-level case, letting a decimal point unconditionally join whatever number is currently being built inside the num list. all test cases passed: \"0.3 + 1.5436* 245\" → ['0.3', '+', '1.5436', '*', '245'] . And, \"3.5\" , \".5\" , \"12.34\" all correctly maintained their decimal points. tested all of the previous test cases like multi-digit numbers, multi-letter function names, parentheses, mixed expressions and all passed . 2. Added Unary minus v/s binary subtraction distinction: While thinking of some more edge cases, I found a case \"2*-3\" → ['2', '*', '-', '3'] which was wrong and I found out that the tokenizer needs to make the distinction between a unary minus -3 , -x , etc. and a binary minus 2-3 , x-4 , etc. Added a special condition for - in the top level operator detecting if block and handling edge cases in the .isdigit and .isalpha elif blocks. All test cases passed:- \"3-2\" → ['3', '-', '2'] \"3*-2\" → ['3', '*', '-2'] \"-2+3\" → ['-2', '+', '3'] \"(-2)\" → ['(', '-2', ')'] \"3--2\" → ['3', '-', '-2'] 3. Added support for new operators and functions: Support for ^ operator by adding it to the top level operator detecting if block . Support for Absolute Value |x| by adding it to the top level operator detecting if block . Support for Fractional Part Function {x} by adding it to the top level operator detecting if block . Support for Greatest Integer Function [x] by adding it to the top level operator detecting if block . Also added these cases inside the unary minus handling if block thus passing all possible test cases. Status: The tokenizer part is complete for now. There are a few changes to be made, like adding support for implicit multiplication. Though, it is something that could be handled by the parser so I will handle it as time comes."}, {"post_id": 24112, "ts": "2026-07-07T14:03:11Z", "hours": 1.9192, "text": "This is the first devlog for my Domain and Range calculator. I have completed making the first part of my custom AST algorithm: the tokenizer. I have used simple string parsing to separate specific terms in the expression. The algorithm handles sequence of characters (like alphabets or digits) as a single term which opens up the world to more complex and some basic and necessary functions like sqrt(), log(), trigonometric and inverse trigonometric functions. I am now going to handle some edge cases and try to functionize or shorten the collection of characters part as I have noticed that The process is same for digit and alphabets so I could potentially shorten the code. I expect this program to fit cleanly into the larger mathematical suit that I am trying to build to support most of mathematics along with support for coordinate geometry but that is something for later."}]...
|
Title: Math Suite by @R10 | Stardance
Devlogs:
Th Title: Math Suite by @R10 | Stardance
Devlogs:
This is the first devlog for my Domain and Range calculator. I have completed making the first part of my custom AST algorithm: the tokenizer. I have used simple string parsing to separate specific terms in the expression. The algorithm handles sequence of characters (like alphabets or digits) as a single term which opens up the world to more complex and some basic and necessary functions like sqrt(), log(), trigonometric and inverse trigonometric functions. I am now going to handle some edge cases and try to functionize or shorten the collection of characters part as I have noticed that The process is same for digit and alphabets so I could potentially shorten the code. I expect this program to fit cleanly into the larger mathematical suit that I am trying to build to support most of mathematics along with support for coordinate geometry but that is something for later.
Tokenizer progress: 1. Added decimal point support: Failed attempt : I initially tried to detect . from inside the .isdigit if-elif loop like detecting a continuation of digits but failed on case "12.34" → ['1234'] and then found the simpler solution. Added elif exp[i] == ".": num.append(exp[i]) as its own top-level case, letting a decimal point unconditionally join whatever number is currently being built inside the num list. all test cases passed: "0.3 + 1.5436* 245" → ['0.3', '+', '1.5436', '*', '245'] . And, "3.5" , ".5" , "12.34" all correctly maintained their decimal points. tested all of the previous test cases like multi-digit numbers, multi-letter function names, parentheses, mixed expressions and all passed . 2. Added Unary minus v/s binary subtraction distinction: While thinking of some more edge cases, I found a case "2*-3" → ['2', '*', '-', '3'] which was wrong and I found out that the tokenizer needs to make the distinction between a unary minus -3 , -x , etc. and a binary minus 2-3 , x-4 , etc. Added a special condition for - in the top level operator detecting if block and handling edge cases in the .isdigit and .isalpha elif blocks. All test cases passed:- "3-2" → ['3', '-', '2'] "3*-2" → ['3', '*', '-2'] "-2+3" → ['-2', '+', '3'] "(-2)" → ['(', '-2', ')'] "3--2" → ['3', '-', '-2'] 3. Added support for new operators and functions: Support for ^ operator by adding it to the top level operator detecting if block . Support for Absolute Value |x| by adding it to the top level operator detecting if block . Support for Fractional Part Function {x} by adding it to the top level operator detecting if block . Support for Greatest Integer Function [x] by adding it to the top level operator detecting if block . Also added these cases inside the unary minus handling if block thus passing all possible test cases. Status: The tokenizer part is complete for now. There are a few changes to be made, like adding support for implicit multiplication. Though, it is something that could be handled by the parser so I will handle it as time comes.
Parser Testing I spent about 4 hours testing and debugging the recursive decent parsing algorithm, trying to understand the flow by writing each and every step. Here are my test cases. Test case-1 exp = 2+3*4 tokens = ['2', '+', '3', '*', '4'] expected result = ('+', 2, ('*', 3, 4)) This test case was used so that i can better understand parse_add and parse_mul along with the main parse_atom. Reached the correct answer. Found a bug in approach: I was not handling the case when pos was out of index ideally. Researched a bit on RDP and found out there is a basic template used in RDP which is while pos < len(tokens) ... and thus used this refined knowledge in my successive attempts. Test case-2 exp = 2+3+4+5 tokens = ['2', '+', '3', '+', '4', '+', '5'] expected result = ('+', ('+', ('+', 2, 3), 4), 5) This specific test case defines why a while loop is important as it includes accumulation of same operator. I wanted to work through this by hand as I was really confused why we need a while loop instead of a simple if-else check whether the pos is out of range or not but the answer became clean when i worked through it. Reached the correct answer. Test case-3 exp = (2+3)*4+1 tokens = ['(', '2', '+', '3', ')', '*', '4', '+', '1'] expected result = ('+', ('*', ('+', 2, 3), 4), 1) I used this test case as it introduces parenthesis into the parsing algorithm which is a fundamental feature. correctly worked through the parsing and reached the correct answer. Parser I also completed the v1 of the parser in just 20 minutes. It is pretty hilarious that it took me 4 hours just to understand RDP but 20 minutes to code it. But, I believe those were 4 hours well spend because earlier, I found RDP to be mind breaking, but now I understand it so well that I think I can teach it even to a 12 year old.
Debugging Day fixed unary negative operation on a function like -sqrt in the tokenizer. added support for implicit multiplication in the tokenizer (right now only valid for alphabets after numbers like 3x, 25x, etc. and not for alphabet after alphabet like xsin(x), xlog(x), etc.) fixed the decimal point collection in the tokenizer due to the failed test case: -.5 Added support for exponents by adding parse_pow() . initially i had simply copied the structure of parse_add and parse_mul and ran the test case but i found out that the result was wrong. My current parsing algorithm has natural left associativity, which is required for other operators but, is wrong for power. Because, 2^3^2 should result in 2^(3^4) and not (2^3)^4, which means i needed right associativity. For getting right associativity, i had to make it such that the right term of the node was recursively calling parse_pow(), so that everything after it would get parsed first which would give us right associativity.
AST Visualizer After completing my tokenizer and parser with a few fixes, I wanted to move straight onto building the actual domain and range logic and setting up all the constraints, but instead, I had another idea. Whenever I saw the output of my parser, it just seemed a bit meh . The output was just a nested tuple and it was not looking like what I had built was a tree. So, as a side quest, I built an SVG AST visualizer that takes the tuple and build its tree and it is SVG and not matplotlib so that if I ever decide to turn this program into a website, I can simply plug in this code and get the output straight in a web page. How it works: For the people curious as to how it works, I am sorry if my explanation does not make sense because even I do not understand it very well (I am pretty bad at recursion). basically, the main function that lets me plot these nodes in a 2D space is assign_positions. If we do not focus on recursion yet, the basic idea of this function is that there are 2 types of node: leaf nodes and internal nodes . Leaf nodes are the nodes which do not have any children and terminate the branch i.e. are terminal . whereas, internal nodes have children and branch out further to extend the tree i.e. are non-terminal . The basic hypothesis was that if there are two leaf nodes, and I assign them an x-position of 0 and 1, their parent node should be at a position which is the mid point (or average) of its children. Which means, the parent node of two leaf nodes (or internal nodes) at x-position 0 and 1 would lie at x-position 0.5 (avg of 0 and 1). now for the y-position, I have used depth as the name where the idea was simply that with every new node, the depth should increase by 1. Now we come to recursion and how I generalized this position idea to any possible tuple. The basic things that the assign_positions function takes are: node-> Current node depth-> Current depth/ y-position id_count-> The ID assigned to the node leaf_count-> Basically the x-position of the leaves tree-> Current tree dictionary There are 2 cases, the node can either be a leaf or an internal node. If the node is a leaf node, then we simple make the tree: tree[str_id] = {'label': node, 'x': str_x, 'depth': depth} . we increase leaf_count by 1 (because if the x-position assigned to this node was 0 then the next leaf node should have it as 1) and we increase id_count by 1. This case returns the x-position assigned to this node-> str_x, the id assigned to this node-> str_id, the current id_count, the current leaf_count and the current tree. These specific constraints are returned because If a parent had done a recursive call and the node was a leaf node then the parent would require: the child’s x position to average left and right positions to set its own position. the child’s id to keep track of it in its own dictionary. the current id_count and leaf_count so that an assigned number is not reassigned to another node by mistake in a recursive call. Case-2 and tree rendering covered in next devlog
AST Visualizer (continued) Case-2 If the node is not a leaf (i.e. not a string) we will again check for 2 cases. the node can either have 1 child or 2 children. If there are 2 children then we have to make 2 recursive calls but if we have a single child then only one and the other stuff is pretty similar so I will only explain the case when there are 2 children. first of all, we unpack the node to get op, left and right. Now we call assign_positions with depth+1 (to effectively track each level we go down), on left and right and extract: x-position of children, id of children and the parameters that get updated (id_count and leaf_count). next, we used children’s x-position, average it to get the op’s x-position. We make the tree: tree[op_id] = {'label': op, 'x': op_x, 'depth': depth, 'children': [l_id, r_id]} . Now we increase the id_count by 1 but not the leaf_count as we have not encountered a leaf (I had made a mistake here and increased leaf_count in the case where the node is not a leaf because I had named the variable as x_position earlier and thought that it must increment everywhere but forgot that we are averaging the children’s x-position to get op’s x-position so i do not need to increment it, which is why I have cleared this up). Now we return the same stuff: op_id, id_count, op_x, leaf_count, tree. Rendering Tree The actual tree generation is simply looping through the dictionary. The important function is converting x_position and depth values that are simple integers into actual pixel positions to actually position the circles in the correct spot which is done by pixel_x = margin+x*x_spacing and pixel_y = margin+depth*y_spacing where margin, x_spacing and y_spacing are all hyper-parameters. The next function is draw_nodes which simply loops though the values of tree dictionary gets the x and depth for each node, converts them to actual coordinated using get_pixel_coords and then creates the svg line: '<circle cx="{x}" cy="{y}" r="25" fill="white" stroke="black" /> <text x="{x}" y="{y}" text-anchor="middle" dominant-baseline="middle">{i['label']}</text>' for each node and its text. The other is draw_lines. It takes all the parent nodes and gets their x and y value as pixel coordinates. Then, it gets the children of the node and for each child’s id, the function gets the child by its id, then gets the x and y coordinates of the child as pixel coordinates and then draws the line as per this syntax: f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="white" />' Finally we have the render_expression function which wraps everything into a single sequence of operations and creates the final svg code: f'<svg xmlns="http://www.w3.org/2000/svg" width="850" height="650"> {lines} {nodes} </svg>' and created an svg file to view the final tree.
Domain Calculation Started the domain calculation file (domain.py) and made the function get_constraints() that recurses through the tree to look for domain restricting operators like /, sqrt, log, arcsin, etc. into a list. next steps are to solve each of the generated constraints (inequalities) and then combine them to get the domain for x (or any variable). Currently working on trying to solve the inequalities but it is proving to be pretty difficult so it could take longer than usual.
It has been a tough journey If you read my previous devlog, it almost feels like i was foreshadowing what was about to happen to me. While making the solve_node function which would solve the inequality for x, i got lost in the mess of symbolic mathematics and started handling cases with fallbacks upon fallbacks. It has really a hot mess, I got to find out that there can be many types of questions and to solve every type of domain question, I would need fallback logic for every type of question which would mean I would have to encompass all the techniques in domain finding into the file and manage the interaction of the techniques and orchestrate them at a high level and basically making my own sympy (which took decades to build). I even thought of quitting a few times and the project was basically at a halt for 1-2 days. I then decided to solve a simple domain question by hand to check what really are the steps of finding the domain of a function. I found out that my logic up until making the constraints was fine. The next steps were finding critical points for example: (x-2)(x+3)>0 would have critical points 2 and -3 (they are just the points where the function is zero). Now, I also know that critical points also occur when the sign of the function changes or when its nature changes (going from defined to undefined and vice-versa) so instead of making a symbolic critical point finding function I thought of a more brute force method. If I have a number line (range of numbers) and i simply walk through them one by one, noting sign change between 2 numbers as a sign “there is a critical point here” and then use another function to basically go into each of those marked intervals and continuously half the interval (think of it as taking an interval and then zooming into the interval until you find the critical point) until about 9 decimal places (could be anything, it is just the amount of accuracy), you would get the critical point pretty accurately without having to solve anything using logic or symbolically, just substitute values of x. After finding the critical points, turning it into domain is as simple as just substituting points and see if the inequality holds.
Union and Intersection of intervals I have made the intersection function which takes intervals and unions them together. I am now working on the union function. I initially used recursion to do the job but that was incorrect that the better method was just to sort the intervals list and then use a simple loop to evaluate the union. Here is the issue i was facing: [[A, B, C, D], E] AUE-> False, BUE-> False, CUE-> True => [F, A, B, D] union [F, A, B, D]-> FUA-> False => [[F,A], B, D] again [F,A], B => FUB-> False, BUA-> False => [F, A, B] => union this list now => FUA-> False => [[F,A], B] then again [F,A], B => FUB-> False, BUA-> False => [F, A, B] => FUA-> False => [[F,A], B] this goes on and on infinitely This is a problem of infinite recursion
Devlog #10 Completed domain.py finished coding domain.py and tested about 20 test-cases on it. Completed debugging to finally finish domain calculation and start with Range. I do not know what else to tell you all as it has been a few days of coding and debugging with different bugs surfacing like incorrect handling of undefined functions, normalizing output, handling union cases correctly, etc.
Derivative For finding the range, I am opting for method of differentiation to check intervals. hence, I have made derivative.py for differentiation. This is my second derivative calculator. The first one that I built was made completely using string slicing and weird string manipulation and pretty biased logic where everything was stored in the form of a dictionary. To be honest, I was pretty proud of that calculator because I was able to make it just using the knowledge I had, and recursion is not innate (I think) and I was still able to do it so I am proud of it. But, it was no doubt pretty inefficient with a lot of edge cases. Therefore, this time i am making a better calculator using my new AST representation and A LOT more recursion. This calculator will process more functions and it will be able to simplify the derivative too, for example: derivative of 2x^2 will not be displayed as 2*2x, rather it will be correctly displayed as 4x.
STUCK So basically, since my last devlog, the main feature of the new derivative calculator that I had proudly announced is now coming to bite me. The simplification is so tough. Let me explain you all the turn of events. (Simplification is still not complete) basically, my initial idea of simplification was just removing all the temporary zeros and ones that were generated by the derivative itself. Then I thought of increasing the initial scope to support some other simplifications like (‘ ’, ‘2’, (’ ’, ‘2’, ‘x’)) should be solved to (‘ ’, ‘4’, ‘x’). I managed to achieve this simplification too but, I found out there are a lot more simplification cases that I need to handle after we get the derivative. for example: x - 3x, which should be simplified to -2x. For that I had to build an approach which would take the coefficient and base then operate on the coefficients for the same bases according to the operator. Therefore, for x the coeff is 1 and then for 3x the coeff is 3 but that is incorrect. In the case of x-3x, the coefficients should be 1 and -3 so that when i add them i get -2 as the final coefficient for x. To do that, I had to switch all binary subtraction expression and turn them into additive unary negative for op = ‘+’ so that x - 3x turns into x + (-3x). Now, all this actually worked but the main problem was that now the flattened list looks like [‘x’, (’ ’, ‘-1’, (‘ ’, ‘3’, ‘x’))] which means I cannot reliably extract the coefficients now. I first have to handle the recursive case of flattening the node again, turning (’ ’, ‘-1’, (‘ ’, ‘3’, ‘x’)) to the flattened version [‘-1’, ‘3’, ‘x’] and then i would have to run it back through combine where it would be formed as calc = -3 and symbols = ‘x’ and then rebuild it as the node (’ ’, ‘-3’, ‘x’). Only after that can i actually extract the coefficients and compare the bases of the two expressions which would be 1 and -3 and calculate them according to the op => ‘+’ to finally give -2 as calc and ‘x’ as symbols and then rebuild that again into (‘ ’, ‘-2’, ‘x’) to solve it. Now this was just one case for one operator but i need to handle both ‘+’ and ’ ’ as the both have associativity and there are other cases for other ops too like x^2/x should just simplify to x. I have already added so much code that I myself feel like the approach is very wrong and the more I build the more edge cases I am adding because right now the amount of if-else handling for specific cases is crazy so I really think that I need to reconsider my approach for simplification. The derivative calculator is taking too much time considering it is an intermediate step but I think it would be worth it because this simplification step is something that I have never done before so I would be learning something anyway.
DEVLOG #13 I have completed the basic simplification functions now but, it is not working perfectly and there are still some changes to be made. for example, handling cases where it is multiplied by 0, or when 0 is added, or it is multiplied by 1, etc. so I think it requires a bit more of iterative debugging to catch all of the edge cases. I have formalized the design of simplification into: Flatten -> form_term -> merge_terms -> form_node -> rebuild which is much better then the previous logic that I had where I was adding more edge cases for handling each case. Right now I will be testing the full recursion for a test case to check where it goes wrong right now in the pipeline to fix it.
DEVLOG #14 Completed the full simplify_initial pipeline. Handled cases with 0 and 1 and traced a full long recursion by hand to better understand the pattern and make iterative debugging faster. Also handled negative node by simplifying the ('*', '-1', right) node formed so that any coefficients collapse cleanly and the term can form correctly with a negative coefficient. EXAMPLE:- Earlier: x - 3x -> terms = [(1.0, 'x', 1.0), (-1.0, ('*', '3', 'x'), 1.0)] Now: x - 3x -> terms = [(1.0, 'x', 1.0), (-3.0, 'x', 1.0)] Therefore, now merging terms will result in ('*', '-2', 'x') I pasted my code into claude and asked it to generate me some test cases which it believes would fail and now I am working on debugging them with a mix of hand tracing recursion and simple fixes so the pipeline is almost at its end (I hope).
DEVLOG #15 Real PROGRESS! Completed the full differentiation pipeline which is working completely now with all edge cases (that I have tested) handled. converted simplify to a standalone file as I noticed that simplify could be used as a general simplification pipeline for ALL generated nodes in my maths suite. Created pow_to_div function in simplify to turn negative exponents into division nodes to make the simplification pipeline truly generalized because none of my other algorithms expect a negative exponent. A LOT of debugging in domain.py and testing some edge cases. Adding support for multiple exclusions instead of single in normalize_domain . Earlier: (-∞, -2) ∪ (-2, 2) ∪ (2, ∞) Now: R-{-2, 2} which is a much cleaner solution Now I am working on completing range.py and then finally making the website for the full maths suite. I am a bit confused. I am not able choose between flask and FastAPI. If you have read all this then would you also mind sharing your opinion on what should I use in the comments?
DEVLOG #16 More PROGRESS! completed range.py tested edge cases with some pretty nasty ones and have decided to leave some limitations like not supporting gif/frac/sec/tan… functions because of their nature. General Debugging created all the flask endpoints along with the basic HTML layout of the website and wiring in the JS. Website is tested and all endpoints are working Now, I will focus on adding some styling to the website and also making the user experience better.
DEVLOG #17 Completed Styling (would appreciate feedback) Features: AST generator AST visualizer (downloadable SVG trees) Domain calculator Range Calculator Derivative calculator Simplification Next steps: AST back to expression generator because right now all the calculators give the result in terms of AST nodes so i need a reverse-parser which I think would be easy. Making a simpler bare bones CLI tool for simpler People. adding a guide page to the website explaining all the limitations and syntax of the calculator. hosting on my own domain? That is all that I can think for now. Right now I have not hosted the website because I am thinking of adding a few more features like user changeable SVG node and line colors, etc.
DEVLOG #18 LIVE PROJECT I have finally deployed the Version-1 of the project on vercel, check it out at the link above. I also completed the README for my repo explaining all the features and limitations of the project. Now I will be working on making an unparser to show the users a clean expressions as a result from the calculator instead of AST nodes and I will also add a guide page on the website for the syntax rules and general guide.
DEVLOG #19 Another Setback I was working on the unparse function today. Basically the idea was simply to recurse through the tree and form the expression as a string. Now, the hard part in this was to decide when to apply parenthesis. Basically, we have to apply parenthesis to any child of the function which has a lower precedence then the current parent op. I did not have this idea as well set in my mind when i was making this function and I just wasted 4 hours today trying to stack up elif cases with or conditions to try to cover every shape. Basically, I was thinking that for * / / , there are only 4 base cases: both children need parenthesis left needs parenthesis right needs parenthesis none need parenthesis I took that as a starting point and then i started to think of cases which would satisfy that and that caused me to build up this or-or-or jargon. I am really pissed. Now I will change my direction and move onto a precedence based approach which checks if the precedence of the child is lesser than the parent op, if yes then parenthesize it and if no then check if precedence is equal, if it is then check for associativity. That is the plan and I hope I don’t mess up this time.
DEVLOG #20 Completed and wired Unparser TRY NEW UPDATE I completed the unparser now with the precedence based approach and I can’t believe how much simpler it is and how bad my initial approach was. The thing that makes it work is the new needs_paren function which basically does all the precedence based logic of telling if the child needs parenthesis or not. Basically if the child’s precedence is lower than the parent op then we need a parenthesis. For example: if the child is a + node and the parent is a * node then we would need parenthesis on the child. For example: (x+1) * 3 -> x+1 needed parenthesis. The main part that made me think a bit was the case when precedence of the child and parent is equal. There are basically 3 cases here: When op is + or * , the child never needs parenthesis. When op is - or / , the child only need parenthesis if it is on the right side. For example: precedence of + == - , a + b - c -> a+b is on the left side and hence does not needs parenthesis. Whereas, c - (a+b) -> a+b on the right side needs parenthesis because this basically means c - a - b and not c - a + b . Hence, parenthesis is required. When op is ^ , parenthesis is only required when the child is on the left and not when it is on the right. For example: a^b^c does not need parenthesis (even though it could be written as a^(b^c) ) but, (a^b)^c needs parenthesis because this means a^(b*c) as the powers multiply. I have also wired in the unparser function to derivative and simplify too so now the result is an expression instead of a tuple. Now I will update my README.md and explain the working of the unparser and then I will work on adding the guide page to my website.
DEVLOG #21 Completed the CLI tool and created binaries for windows and linux using pyinstaller. Also completed the full Guide page on the website with all the relevant rules, syntax and limitations listed cleanly....
|
1792536654.8553803
|
1793141454.8553803
|
|
28672
|
Helpy by @Ak_45 | Stardance
|
|
2
|
105.33
|
307
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-02T08:59:48Z", "hours": 38.0, "multiplier": 12.68, "payout": 237, "blessing": "neutral", "text": "I have polished the previous version of the app. I have added a focus shield, a music and ambient noise player, an AI chatbot, a softer notification, and better personalization. Completely discarded the previous version of the Chrome extension and rewrote it and added better UI and smart web tools, making it so that you can customize the user’s plan from the Chrome extension itself. Made the bridge between the app and the Chrome extension smoother and better & made the app way more ADHD-friendly. # NOTE: make sure that you enable notification in your OS and BROWSER", "repo": "https://github.com/Akshithsurya/helpy", "demo": "https://github.com/Akshithsurya/helpy/releases/tag/Helpy"}, {"ship_num": 2, "ts": "2026-07-15T14:50:47Z", "hours": 16.0, "multiplier": 8.66, "payout": 70, "blessing": "neutral", "text": "Helpy is a cross-platform desktop application built with Electron, accompanied by a Chrome extension, to help individuals with ADHD manage tasks, improve focus, and reduce distractions. The project was designed around the idea that productivity tools should adapt to the user rather than requiring the user to adapt to the tool. The application combines task management, focus sessions, reminders, and browser integration into a single, streamlined experience. The Chrome extension allows users to quickly capture tasks while browsing, while the desktop application provides a centralized workspace for organizing and tracking progress. One of the primary challenges was integrating the Electron desktop application with the Chrome extension while maintaining a consistent user experience. Packaging the application for distribution across multiple platforms and designing an interface that remains simple without sacrificing functionality also required significant effort. This project strengthened my understanding of Electron, Chrome Extension APIs, desktop application packaging, application architecture, and user-centered interface design. I am particularly proud of creating a solution that addresses a real accessibility and productivity challenge while remaining easy to install and use. To test the project: Download and install the latest release from the GitHub Releases page. Launch the Helpy desktop application. Load the Chrome extension using Chrome’s Developer Mode (Load unpacked or install the provided package). Create tasks, start focus sessions, and use the extension to save tasks directly from the browser. Verify that tasks and productivity features function as expected.", "repo": "https://github.com/Akshithsurya/helpy", "demo": "https://github.com/Akshithsurya/helpy/releases/tag/Helpy"}]...
|
[{"post_id": 50212, "ts": "202 [{"post_id": 50212, "ts": "2026-08-19T10:56:53Z", "hours": 8.6908, "text": "chnaged many of the features compressed to exe but i got hit with an error"}, {"post_id": 48032, "ts": "2026-08-16T10:05:38Z", "hours": 8.5569, "text": "Ready for ship and made the UI better and made it better and less quirky"}, {"post_id": 46824, "ts": "2026-08-14T10:51:45Z", "hours": 8.3019, "text": "made the chatbot better and added better code to everything and majour ui chang(rn place holder)"}, {"post_id": 45592, "ts": "2026-08-12T05:49:31Z", "hours": 8.6422, "text": "Made the features take up less space, which shrunk the app by 31%, and then made the notifications less annoying, made the app a bit more chat bot driven and made the chat bot better and added better themes"}, {"post_id": 40695, "ts": "2026-08-04T11:47:31Z", "hours": 8.8981, "text": "Added so that the app picks up the timer if you closed the app, made the music selection better and added new welcome message for new users to get started. :)"}, {"post_id": 40022, "ts": "2026-08-03T11:27:17Z", "hours": 8.24, "text": "I have made the chatbot better, made the UI better and less cluttered, added better focus shield, and made it way more optimised"}, {"post_id": 39305, "ts": "2026-08-02T06:06:20Z", "hours": 7.6078, "text": "Done adding a less cluttered UI, personalization, a chatbot companion, and more music and about to release V2"}, {"post_id": 38153, "ts": "2026-07-31T12:17:00Z", "hours": 8.9819, "text": "Major UI makeover and added a better chat bot."}, {"post_id": 36445, "ts": "2026-07-28T16:00:06Z", "hours": 8.1717, "text": "Added a chatbot and optimized the code & added features to help people with dyslexia to operate it."}, {"post_id": 34076, "ts": "2026-07-24T15:18:57Z", "hours": 8.3667, "text": "Added a settings row to Focus Focus Shield, Calm Mode, No Animation, Light Mode toggle, and a font/sound switcher. Added a settings row to Focus Focus Shield, Calm Mode, No Animation, Light Mode toggle, and a font/sound switcher. Per User Persistence All Per User Persistence All Also built Quick Commands - one input to type stuff like /plan work 60 or /help instead of clicking through menus. Still wiring up the rest of the commands. Underneath that: Create Focus Plan, with a Timer: Work Mode. Right now it just displays 00:00 as a placeholder – next up is hooking it to the actual session logic so starting a plan counts down for real.:)"}, {"post_id": 30564, "ts": "2026-07-18T07:36:40Z", "hours": 4.5017, "text": "Dark mode has been added. Now tell me what else i should add?"}, {"post_id": 28892, "ts": "2026-07-15T14:17:59Z", "hours": 1.9361, "text": "made the signup and login work made the notifications way less annoying :D"}, {"post_id": 27758, "ts": "2026-07-13T16:30:41Z", "hours": 2.1161, "text": "Added a Chrome extension to help track activities and to help people with ADHD and ADD"}, {"post_id": 27167, "ts": "2026-07-12T14:16:42Z", "hours": 2.9783, "text": "UI ready"}, {"post_id": 26023, "ts": "2026-07-10T16:30:57Z", "hours": 9.1939, "text": "Working on HelpY, a project to help ADHD and forgetful people, but how do fix this error? No AI agent was able to make a dent in the problem."}]...
|
Title: Helpy by @Ak_45 | Stardance
Devlogs:
Worki Title: Helpy by @Ak_45 | Stardance
Devlogs:
Working on HelpY, a project to help ADHD and forgetful people, but how do fix this error? No AI agent was able to make a dent in the problem.
UI ready
Added a Chrome extension to help track activities and to help people with ADHD and ADD
made the signup and login work made the notifications way less annoying :D
Dark mode has been added. Now tell me what else i should add?
Added a settings row to Focus Focus Shield, Calm Mode, No Animation, Light Mode toggle, and a font/sound switcher. Added a settings row to Focus Focus Shield, Calm Mode, No Animation, Light Mode toggle, and a font/sound switcher. Per User Persistence All Per User Persistence All Also built Quick Commands - one input to type stuff like /plan work 60 or /help instead of clicking through menus. Still wiring up the rest of the commands. Underneath that: Create Focus Plan, with a Timer: Work Mode. Right now it just displays 00:00 as a placeholder – next up is hooking it to the actual session logic so starting a plan counts down for real.:)
Added a chatbot and optimized the code & added features to help people with dyslexia to operate it.
Major UI makeover and added a better chat bot.
Done adding a less cluttered UI, personalization, a chatbot companion, and more music and about to release V2
I have made the chatbot better, made the UI better and less cluttered, added better focus shield, and made it way more optimised
Added so that the app picks up the timer if you closed the app, made the music selection better and added new welcome message for new users to get started. :)
Made the features take up less space, which shrunk the app by 31%, and then made the notifications less annoying, made the app a bit more chat bot driven and made the chat bot better and added better themes
made the chatbot better and added better code to everything and majour ui chang(rn place holder)
Ready for ship and made the UI better and made it better and less quirky
chnaged many of the features compressed to exe but i got hit with an error
Ships:
Helpy is a cross-platform desktop application built with Electron, accompanied by a Chrome extension, to help individuals with ADHD manage tasks, improve focus, and reduce distractions. The project was designed around the idea that productivity tools should adapt to the user rather than requiring the user to adapt to the tool. The application combines task management, focus sessions, reminders, and browser integration into a single, streamlined experience. The Chrome extension allows users to quickly capture tasks while browsing, while the desktop application provides a centralized workspace for organizing and tracking progress. One of the primary challenges was integrating the Electron desktop application with the Chrome extension while maintaining a consistent user experience. Packaging the application for distribution across multiple platforms and designing an interface that remains simple without sacrificing functionality also required significant effort. This project strengthened my understanding of Electron, Chrome Extension APIs, desktop application packaging, application architecture, and user-centered interface design. I am particularly proud of creating a solution that addresses a real accessibility and productivity challenge while remaining easy to install and use. To test the project: Download and install the latest release from the GitHub Releases page. Launch the Helpy desktop application. Load the Chrome extension using Chrome’s Developer Mode (Load unpacked or install the provided package). Create tasks, start focus sessions, and use the extension to save tasks directly from the browser. Verify that tasks and productivity features function as expected.
I have polished the previous version of the app. I have added a focus shield, a music and ambient noise player, an AI chatbot, a softer notification, and better personalization. Completely discarded the previous version of the Chrome extension and rewrote it and added better UI and smart web tools, making it so that you can customize the user’s plan from the Chrome extension itself. Made the bridge between the app and the Chrome extension smoother and better & made the app way more ADHD-friendly. # NOTE: make sure that you enable notification in your OS and BROWSER...
|
1792983285.2761765
|
1793069685.2761765
|
|
21914
|
MIRA - Machine Intelligence for Recycling by @jere MIRA - Machine Intelligence for Recycling by @jeremy | Stardance...
|
jeremy
|
1
|
105.04
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-02T14:58:05Z", "hours": 89.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "MIRA — Machine Intelligence for Recycling Automation Project Overview MIRA is a computer-vision system designed to identify recyclable materials and prepare the results for automated sorting. Its purpose is to connect camera and robot arm. For automated trash recycling The system recognizes five material classes: glass, metal, paper, plastic, and trash. it utilizes YOLO11n models for the base and is selftrained on mutiple opensource datasets from various soruces MIRA ia also more than just a model file. It includes a full research pipeline for model training with the following features, registering datasets, merging sources, remapping labels, validating YOLO annotations, creating reproducible splits, training detectors, evaluating results, benchmarking models, and exporting them for different environments. To do that it uses a command-line interface which can run live inference, starts the dashboard, manages datasets and models, launches training, evaluates detectors, compares performance, exports formats, and runs diagnostics. MIRA supports 3 kinds of models FP32 PyTorch model, an ONNX and an INT8 TFLite export. The TFlite versions is meant for rasberry pis though benchmarks are still missing Mira also posses a dedicated website. For information and docs.", "repo": "https://github.com/jeremy341/MIRA-AI", "demo": "https://mira-vision.vercel.app/"}]...
|
[{"post_id": 55660, "ts": "202 [{"post_id": 55660, "ts": "2026-08-27T16:51:22Z", "hours": 10.2483, "text": "MIRA - Revision 2 This phase was just about bug fixin, way to many bugs i dont know where they even came from. Pipeline I first started with the research pipeline for some reason it wasnt really activated like the CLI wasnt running because I initialied the pipeline in the wrong order so I fixed that. Camera Engine After the reviewer came back to me and told me that my camera engine for the dashboard wasnt working I say down and did a whole redesign to make sure it works and looks good. The main bug was just as before that I didnt cover edge cases and initailised the camera engine in the wrong order. #Website I did another redesing of the website though not much changes i just rewrote logic and cleaned up the docs page again. Next Steps So first of all for some reason this devlog is 10 hours idk how its this much prob a kind of bug which I need to analyse. I will now continue cleaning up the entire codebase for bugs and hopefully push it one last time and get accepted"}, {"post_id": 52246, "ts": "2026-08-22T10:43:11Z", "hours": 5.7886, "text": "MIRA - Revision This devlog is about fixing bugs and redoing parts of my website. It seems like my project won’t be approved because of the website and the amount of AI used for it, which I fully understand. There is just one problem: the website was never the focus of MIRA. It is purely aesthetic and was made so people can get a quicker overview of the project. Still, I complied and rewrote around 1000 lines of code, changing spacing, logic and other parts of the website. But it is still not being approved, so the next step is creating a separate, simpler website just for Stardance so the project can finally be approved. Bugs While working on the website, I wanted to test the dashboard and noticed that it didn’t seem to work anymore. I analyzed what was wrong but couldn’t really understand why. The dashboard was my first experience using FastAPI, but from the logic I understood, it should have worked. It just didn’t. So instead of trying to patch it, I decided to redo the whole backend logic of the dashboard and adjust it to work more like MIRA Live. This fixed the bug, but even afterwards I still couldn’t fully figure out what exactly caused the old version to stop working, even after asking AI and going through the code multiple times. As it had been working before Website Redesign Before deciding to create a completely separate website as mentioned above, I tried redesigning and cleaning up the current website as much as possible. I didn’t touch the color palette because I chose it myself for a specific reason, and I honestly can’t identify MIRA with another color scheme anymore. Instead, I removed things I wouldn’t have been able to code myself, like certain slide-in animations and more complicated spacing. I also rewrote parts of the logic that I didn’t properly understand before and replaced them with simpler solutions that I actually understand. Next steps Hopefully i can get approved soon and will be able to finnaly work on the next project. Iam probally goint to try one more time to redesign the website and if that doesnt work I will create a new one which i just think is unecssary, because as I said MIRA is a computer vision model and research pipeline coded mostly by hand and the website was just generated quickly for asthetic reasons and truth be told isnt necessary at all"}, {"post_id": 39514, "ts": "2026-08-02T14:51:06Z", "hours": 2.6247, "text": "Last Devpost Created the Website but a lot of time was lost as for some reason hackatime didnt track I am now finished couldnt bother to write a real devpost this time https://mira-vision.vercel.app/"}, {"post_id": 38961, "ts": "2026-08-01T16:09:09Z", "hours": 8.2483, "text": "MIRA — Day 15: Repository Cleanup, EXP-019, and Reproducible Results This time Instead of adding more features, I concentrated on making the existing software easier to understand, easier to reproduce, and just better overall. The main outcomes were a big repo cleanup, New kaggle results with EXP018/019 reaching all time high of mAP50 of 90% Repository Cleanup and Reliability Improvements I performed another detailed check of the complete codebase. Which highlightes some more issues as a lot of code was Ai generated. The review uncovered problems in both the runtime software and the research CLI/pipeline. I cleaned up third party model files, duplicate documentation, archived ZIP files, and unused assets such as Datasets. The local repo had previously grown to ca 13 GB , largely because of old Git objects. After the cleanup, it was reduced to approximately 520 MB . The README was reduced from roughly ** 900 lines** to approximately 340 lines . It now concentrates on the current installation process, the active perception pipeline, the best available models, dataset origins, known limitations, and reproducibility. Jugend forscht material was moved into the jufo/ directory, while the related-work section was separated into its own document and was put in gitignore for various reasons. EXP-018 and EXP-019 After rebuilding the dataset and correcting the training workflow, I trained YOLO11n on the cleaned and balanced dataset. EXP-018 achieved the following results: Metric Result mAP50 90.6% mAP50-95 82.2% Glass mAP50 90.8% Metal mAP50 94.8% Paper mAP50 88.7% Plastic mAP50 81.1% Trash mAP50 97.5% Compared with EXP-014, which achieved 60.7% mAP50 on the older dataset, this represents an improvement of 29.9 percentage points . I repeated the training as EXP-019 to test whether the result was reproducible. EXP-019 again achieved 90.6% mAP50 on the same clean dataset. So EXP-019 is now the best Model and the final one Model Exports The EXP-019 was exported into multiple formats for later deployment tests: Format Approximate size Intended use FP32 PyTorch 5.5 MB Development and reference inference INT8 TFLite 2.90 MB Resource-constrained edge hardware ONNX 10.1 MB Cross-platform inference and benchmarking The INT8 TFLite version is especially important for the planned Raspberry Pi Zero 2 W deployment. Its smaller size should reduce storage and memory pressure, although its real speed, temperature, and accuracy still need to be measured on the target hardware. Next Steps The next task is to benchmark EXP-019 on the Raspberry Pi Zero 2 W ordered through Stardance. The test will measure: Inference speed and end-to-end latency. Memory usage. Temperature during continuous operation."}, {"post_id": 37701, "ts": "2026-07-30T16:30:22Z", "hours": 9.6736, "text": "MIRA — Day 14: Dataset Rebuild, Failed Kaggle Runs, and JuFo Preparation Today focused on making MIRA scientifically reliable instead of simply adding more features. I completed another full codebase revamp, checked two failed Kaggle training runs, rebuilt the waste dataset, improved the training workflow, and rewrote the Jugend forscht report. Codebase Audit and Bug Fixing I reviewed the complete Python codebase as about 50% is ai generated and I really didnt take the time to verfiy everything. Important fixes included: Repairing dashboard crashes caused by missing runtime fields and an incorrect performance-metrics function call. Preventing camera shutdown from releasing the camera while another thread was still reading from it. Adding bounded shutdown handling so a blocked camera driver cannot freeze the application. Fixing the custom mAP implementation, which previously allowed predictions from one image to match ground-truth boxes from another image. Preventing export: YAML sections from being passed to Ultralytics as invalid training arguments.. Correcting generated Kaggle and Colab dataset YAML files. Dataset Research and Reconstruction I wanted to train new models so yolo11n and the new yolo26n so I created new datasets. I processed TACO, TrashNet, Roboflow, dmedhi, Keremberke, WaRP, and SortWaste. Keremberke was excluded because its class remapping would have cuased generated approximately 45,000 misleading trash annotations and pushed trash to 40% of all annotation which create an imbalance SortWaste was removed after it showed that most pictures were from the same perspective and always plastic. The rebuilt dataset uses only dmedhi, TACO, Roboflow, and SAM-labeled TrashNet . 5,108 training images 415 tabletop validation images 1,375 independent test images 6,898 unique images 12,832 bounding boxes The training split is approximately balanced, with 1,621–1,982 boxes per class . The final zip is ca 3.6GB Failed Kaggle Training Attempts I ran kaggle scripts overnight and in these was the sortwaste dataset included which gave me these results. Also i did the mistake of running yolo11x and not n whihc explains the 26 epochs even though it ran for 9 hours. YOLO26n 188 epochs 29.1% mAP50 Plastic: 59.7% Trash: 5.4% **YOLO11x ** 26 epochs 20.9% mAP50 Trash: 2.3% These runs were not downloaded or treated as valid results. As they were so bad I didnt want to document them in any kind I ran a new kaggle script for yolo11n with the new cleaned datasets which hopefully has better results. Jugend forscht Report Revision I checked the LaTeX report against the official Jugend forscht requirements. The previous version exceeded the page limit and was quite frankly just bad and build on a lot of assumption so a big part of today was just rewriting it Next Steps I am currently waiting for the YOLO11n training results. The YOLO26n run is planned for next week, as the failed training attempts exhausted my available Kaggle usage. Afterwards, I will benchmark the final model on the Raspberry Pi Zero 2 W I ordered through Stardance. Once the edge-hardware evaluation is complete, I can finalize MIRA and begin planning and building the robot arm."}, {"post_id": 34063, "ts": "2026-07-24T14:56:41Z", "hours": 10.1594, "text": "MIRA — Day 13: Backend Bug Cleanup, Test Suite Expansion, and AI Tooling Today was split between fixing silent backend bugs in MIRA-AI, expanding my test suite to 120 passing tests, and configuring my external AI development tools. Backend Bug Cleanup I ran a full diagnostic check across the codebase and resolved 15 specific bugs: Duplicate Camera Service: Found and removed a bug in main.py that was initializing two separate camera service instances on startup. TFLite Tracking Guard: Disabled ByteTrack tracking when running TFLite models in camera_service.py , since TFLite inference doesn’t support ByteTrack tracking. Modern FastAPI Lifecycle: Migrated from deprecated on_event handlers to the modern asynccontextmanager lifespan pattern across my API services. Code Quality: Updated remaining deprecated .dict() calls to .model_dump() for Pydantic v2, fixed an immutable frozenset cleanup bug in my tests, and resolved 183 Ruff linter warnings. Expanding the Test Suite to 120 Tests I wrote new unit test suites for previously uncovered backend modules: Dashboard Models & WebSockets: Added 30+ tests covering Pydantic model serialization and boundary conditions, plus 15+ tests for WebSocket event callbacks and metric queuing. Test Isolation: Fixed a bug in test_logger.py where the root logger was leaking state between test runs, and fixed brittle Python version checks in test_serialization.py . Current Status: My test suite is now sitting at 120 out of 120 passing tests with 0 Ruff lint errors. AI Developer Tooling & DigitalOcean Outside the core MIRA repository, I spent time configuring my external OpenCode AI setup across multiple providers (OpenRouter, local Docker, Ollama, and GitHub Copilot): Fixed an endpoint URL misconfiguration in my OpenRouter settings and tested connectivity across 23 models. Added handling for “reasoning models” that return output in a reasoning field rather than standard content. Researched how to use my $200 DigitalOcean student credit before it expires on July 31st. Since student credits cannot be applied to GPU Droplets, I plan to deploy a 128 GB Memory-Optimized CPU Droplet to run Ollama with 70B models for offloaded testing. Next Steps Hardware Benchmarks: Run real-world FPS and latency tests on a Raspberry Pi Zero 2W. Trash Class Data: Collect targeted training data for the general “Trash” class, which remains my weakest class at 7.1% mAP50. Also go over the website cause it looks pretty ai generated right now"}, {"post_id": 33074, "ts": "2026-07-22T17:30:48Z", "hours": 10.7814, "text": "MIRA — Day 12: Codebase Audit, EXP-017 Results, and Cross-Platform Fixes Before diving into codebase fixes, I finished training EXP-017 on Kaggle using the merged mira_all dataset. It reached 59.3% mAP50 —which is slightly below EXP-014’s 60.7% . This confirmed a key lesson for me: dataset quality and class balance matter far more than sheer image count. After that, I shifted my focus to running a full diagnostic audit of my codebase to clean up bugs and edge cases. Fixing the Health Check My health check command ( mira doctor ) was crashing immediately on Windows with a UnicodeEncodeError due to special status symbols ( ✓ , ✗ , ⚠ ). I replaced them with plain ASCII characters ( [OK] , [!] , [FAIL] ). Added checks for missing camera backends on Linux so the health check runs cleanly end-to-end regardless of the OS. Making Torch and TensorFlow Optional MIRA supports both PyTorch ( .pt ) and TFLite ( .tflite ) models, but requiring both libraries installed was frustrating—PyTorch alone takes up over 800 MB. I refactored my model adapters and dashboard to use lazy-imports. If PyTorch isn’t installed, PyTorch models gracefully report as unsupported without crashing the application. This allows a lightweight setup without forcing massive unnecessary downloads if someone only wants to run TFLite models on edge hardware. Cross-Platform & Service Hardening I cleaned up my startup scripts and hardened my camera service against common edge-case failures: Updated mira.bat with PYTHONUTF8=1 for Windows, and created a native mira.sh for Linux and macOS. Added OS guards around the Windows-specific DirectShow camera backend. Fixed a potential division-by-zero crash when video FPS drops to zero. Switched Linux CPU temperature reads to psutil instead of hardcoding 0°C. Ensured the model object memory is properly freed on shutdown. Security, Pydantic v2, and Edge Cases Security: I restricted CORS in my web dashboard from wildcard access ( * ) to localhost ( 127.0.0.1:8000 ). Pydantic Upgrade: Replaced deprecated .dict() calls with .model_dump() for Pydantic v2 compatibility. Integrity: Explicitly forced UTF-8 encoding on all YAML file reads, and added SHA-256 hash verification to mira download . Current System Status After resolving these issues, my test suite is sitting at 99 out of 99 passing unit tests , my Ruff linter reports 0 errors , and all 17 CLI commands are fully functional. I also prepared my HackClub StarDance submission writeup and updated the main README with current CLI specs and experiment data. Next Steps Hardware Benchmarking: Measure real-world FPS and inference latency on a Raspberry Pi Zero 2W. Trash Class Data: Collect targeted training images to improve the general “Trash” class, which remains my weakest performer (7.1% mAP50). in this pic you can see a sneakpeak to a new feature"}, {"post_id": 31477, "ts": "2026-07-19T21:36:10Z", "hours": 9.485, "text": "MIRA — Day 11: Dashboard Redesign, Dual Modes, and EXP-017 Datasets Today was all about front-end overhauls and preparation for my next training run. I redesigned my web interface, split it into two dedicated operating modes, and finalized my biggest dataset merge yet to prepare for training EXP-017. Clean Light Theme Dashboard I shifted the entire MIRA web dashboard from my old dark theme to a clean light theme with a mutiple colors. JUFO vs. Stardance Modes I introduced two separate dashboard modes that I can select on-the-fly using URL parameters: JUFO Mode ( ?mode=jufo ): A technical view tailored for competition judges, featuring deep metrics, historical training graphs, and real-time backend diagnostics. Stardance Mode ( ?mode=stardance ): An interactive, simplified playground designed for quick live demonstrations with clean control toggles. System Health & Live Settings I replaced my static history table with a real-time System-Health panel displaying CPU, RAM, temperature, and inference latency using animated progress bars. I also added an “Einstellungen” (Settings) tab to Stardance mode, allowing me to adjust model weights (via a dynamic API model picker), confidence thresholds, IoU, and camera resolution directly from the web UI without needing to restart the Flask backend. Threaded Camera Pipeline My camera stream was bottlenecking my inference engine. I decoupled the frame capture from the detection loop by moving the capture process into a dedicated Python threading.Thread . The web stream now runs at a smooth 20 FPS at 320px resolution. I also patched Camera.release() to verify the stream is open before shutting down, preventing a common camera-close crash. Datasets & EXP-017 Preparation I successfully merged all four of my data sources (TACO, TrashNet, Roboflow, and WaRP) into a unified dataset named mira_all . It contains 9,774 images across 5 classes. While generating the ZIP file, I hit an archive path encoding issue that broke folder hierarchies. I solved this by using just the normal windows option to zip files instead of the powershell way which I wanted to test out My current baseline model (EXP-014) is still performing well with an 85.8% F1-score on my field benchmark, though the general “Trash” class remains my weakest spot at 37.6% due to how much random variation “trash” actually has. Pipline I also worked on pipline and am working on making it plug play allowing user to get any 3rd party model plug it in and use the full research pipline to retrain it compare it benchmark it and do a lot of stuff. I also added the option to add custom datasets and expanded on the CLI with mutiple custom commands this is probally, the second last post because I am nearly finished. The ui for the dashboard was made with ne gpt 5.6 sol because I just couldnt come up with a good ui. Next Steps Train EXP-017: Upload the clean mira_all dataset and run training on Kaggle. Logger Analysis: Review the data from my new last_per_class.json file to see which items are being misidentified during continuous live runs."}, {"post_id": 30068, "ts": "2026-07-17T11:02:10Z", "hours": 9.7753, "text": "MIRA — Day 10: Removing Streamlit, Safety, and Purging my LLM Tools I spent the last week cleaning up a massive amount of technical debt. After about 40 commits, touching 168 files, and adding 6,186 lines of code while removing 1,200 lines of old code, the repo is finally much cleaner. The biggest changes were replacing Streamlit with a Flask-SocketIO server, auditing my project for the Jugend Forscht competition, and removing my custom AI development tools (which I built earlier to help me write code). Replacing Streamlit with Flask + SocketIO Streamlit was a bottleneck for real-time video streaming and thread-safe operations because it re-runs the entire script on user interaction. The Architecture: I built a custom Flask and SocketIO dashboard under src/dashboard_flask/ . Live camera frames are captured in a background thread, encoded to JPEG, and pushed over WebSockets. Thread Safety: I implemented four threading locks to prevent race conditions: camera_lock , model_lock , inventory_lock , and config_lock . Bugs Fixed: I resolved an unnecessary BGR-to-RGB conversion that was washing out my live camera colors, and wrapped my configuration updater in config_lock to prevent multi-thread memory corruption. Modularizing my Inference Pipeline To clean up the backend, I consolidated all duplication: I deleted the separate live and debug scripts, merging their logic into a single src/inference_engine.py module. This engine handles the threaded camera feed, YOLO11n prediction loop, and my BYTETrack fallback. All paths, labels, and parameters are now centralized in src/config.py . Purging my Custom AI Tools I built a terminal-based AI coding assistant to help me write and modify code. However, after an architectural review, I decided it does not belong in this repository. The Reason: MIRA stands for Machine Intelligence for Recycling Automation. The codebase should focus strictly on computer vision and robotics, not LLM wrappers. The Separation: I separated all AI coding utilities into a new MIRA-DevTools repository, which I will start as I near the end of MIRA. JUFO Competition Audit & Paper Since this project is for Jugend Forscht, I have been heavily working on my scientific paper (which I realized I haven’t actually mentioned in previous updates). AI Audit: I ran an AI-assisted audit against JUFO evaluation criteria. It originally rated my project at a 6/10 because my paper lacked a deep discussion section and YOLO11n graphs. The Fixes: I expanded my analysis on how the WaRP dataset’s class imbalance skewed my trash predictions, and compiled a 22-page LaTeX report with proper bibliographies and training curves. Quality Assurance: I added 17 unit tests and automated GitHub Actions with Pytest and Ruff. I will translate the paper to English and upload it soon. Next Steps Folder Cleanup: Run git-filter-repo to shrink my 17 GB folder by removing cached datasets before pushing to GitHub. Final Training: Train one last model on my optimized dataset combination once my Kaggle GPU hours reset."}, {"post_id": 28506, "ts": "2026-07-14T20:00:38Z", "hours": 8.2939, "text": "MIRA Day 9: YOLO11 Migration, INT8 Issues, and Dataset Analysis Over the last few days, I focused on improving the project structure, simplifying the codebase, and testing different approaches for the detection pipeline. I made around 15 commits, added roughly 2,200 lines of code, and removed around 1,000 lines that were duplicated or no longer needed. The main changes were migrating from YOLOv8n to YOLO11n, creating an automated benchmark script, and investigating why some dataset combinations performed worse than expected. YOLO11 and Dataset Experiments I moved from YOLOv8n to YOLO11n because it is better suited for edge deployment while keeping the model lightweight. Since MIRA is intended to run on limited hardware, inference speed and efficiency are important. To test different training setups, I trained four model variants using Kaggle T4 GPUs. I compared several datasets: TACO: Outdoor litter images. TrashNet: Clean recycling images from controlled environments. Roboflow Trash Detection: Waste images with bounding box annotations. WaRP: Industrial recycling images from conveyor belt environments. The best results came from combining TACO, TrashNet, and Roboflow. This combination performed better during live camera tests because it contained both clean object images and more realistic trash scenarios. Why WaRP Reduced Performance Adding WaRP unexpectedly reduced the performance of my general “Trash” class. The reason was a dataset imbalance. WaRP contains many detailed recycling categories like plastic, glass, metal, and cardboard, but it has very few examples matching my general trash category. After mapping WaRP’s classes into my five target classes, most additional training data was added to recyclable categories. This caused the model to become more focused on plastic, paper, and glass while becoming less reliable at detecting mixed waste. This showed that more training data does not always mean better results. The distribution and relevance of the data are equally important. INT8 Quantization Problem While testing my INT8 TFLite model, I noticed that the detection rate was almost zero. The model itself was working, but my confidence filtering removed valid detections. After INT8 conversion, the output confidence values changed compared to the original model. Some detections that previously passed a 0.50 confidence threshold were now below it. Because my pipeline still used the old threshold, valid detections were discarded. I updated the benchmark and live detector to automatically use a lower confidence threshold for INT8 models. After this change, detections worked correctly again. Code Cleanup and Fixes I found several duplicated parts in the project, especially multiple versions of the bounding box drawing logic. I centralized these functions and cleaned up configuration and path handling. I also fixed two problems in the live detection system: Tracker dependency issue: The detector previously used BoT-SORT by default, which caused problems if the required package was missing. I changed the fallback system to use BYTETrack first. Double confidence filtering: Confidence filtering was happening both during prediction and again during visualization. I moved this into one centralized post-processing step to avoid removing valid detections. Repository Cleanup The project folder has grown to around 17 GB because of duplicated datasets, training results, logs, and model checkpoints. Before pushing everything to GitHub, I need to clean the Git history, improve the .gitignore , and remove unnecessary files. The goal is to reduce the repository size to below 500 MB. Next Steps Clean the repository and remove large unused files. Train the final model with the improved dataset combination. Generate evaluation graphs and confusion matrices for the final documentation."}, {"post_id": 25966, "ts": "2026-07-10T14:30:48Z", "hours": 8.3986, "text": "MIRA — Day 8: The Invisible Boxes (and Why Two Models Were Lying to Me) BUGS After hours of digging through Ultralytics internals with AI assistance, I found not one but three separate bugs all stacking on top of each other. Bug #1: Tracker Ultralytics 8.4.84 silently switched the default tracker from ByteTrack to something called TRACKTRACK . I never asked for this. Nobody told me. TRACKTRACK has internal confidence thresholds that are absurdly high: track_high_thresh: 0.6 # Only detections >= 0.6 are “real” new_track_thresh: 0.7 # New objects need >= 0.7 to be tracked Here’s the problem: INT8 quantization drops confidence scores by 20-40%. So a detection that would score 0.55 in the original PyTorch model now scores ~0.35 after quantization. TRACKTRACK looks at 0.35, says “too low,” and silently throws it away. No error. No warning. Just… gone. Bug #2: The Double Filter Even if TRACKTRACK somehow kept a box, my drawing function had its own confidence filter set to 0.5. So a box at conf=0.4 that survived the tracker got killed again at the drawing stage. Bug #3: Nothing Stopped the User from Loading the Wrong Model Nothing in the code prevented me from loading mira_classifier_int8.tflite — a classification model — into the detection pipeline. Which i failed to realise. The code just checked if the file ended in .tflite and said “sure, load it as a detector.” It would’ve failed silently or produced garbage. live_detection.py — The Big One I rewrote the core inference loop. Three major changes: Forced ByteTrack everywhere. PyTorch models now explicitly use tracker=\"bytetrack.yaml\" instead of whatever Ultralytics defaults to. No more silent tracker swaps. Bypassed the tracker entirely for INT8 models. TFLite INT8 now uses model.predict() instead of model.track() . No tracker = no threshold filtering = boxes actually appear. Conf is auto-overridden to 0.25 at startup because INT8 models need lower thresholds. Added model validation. If you try to load a classifier model into the detection pipeline, you now get a clear error: ERROR: ‘mira_classifier_int8.tflite’ is a CLASSIFIER model, not a detector. Live detection requires a detection model (.pt or detection .tflite). Use ’mira eval-class –model mira_classifier_int8.tflite –exp ’ instead. No more silent failures. dashboard.py — Same Story, Streamlit Edition The Streamlit dashboard had the exact same tracker and threshold bugs. Fixed identically: ByteTrack forced, INT8 models use predict(), classifier models filtered from the sidebar before you can even select them. cli.py — First Line of Defence Updated cli.py and added mutiple new commands to make it easier to use also made it possible to use in the termnail through a bat file so u can run the scripts in powershell if you want if you just add .\\mira and then commands. Also Added validation in the live subcommand so classifier models get rejected before the subprocess even spawns. Faster error, cleaner output. Folder Cleanup Reality Checked the project size today: 17.3 GB. That’s absurd for a recycling classifier. Most of it is: Failed experiment outputs Raw dataset images that should’ve been gitignored Multiple copies of the same model in different formats Private test data that never should’ve been committed Need to do a serious cleanup before pushing anything. What’s Next Downloading three new datasets to retrain on: SortWaste (WACV 2026) — real conveyor belt images, 87k bounding boxes TACO — waste in wild environments (forests, streets, beaches) NAVER Recycle Trash — 21k images, indoor + outdoor Target: Combine everything into ~20,000 images, retrain with YOLO11n, hit 80%+ mAP50 with actual real-world robustness."}, {"post_id": 22013, "ts": "2026-07-04T07:57:54Z", "hours": 1.6619, "text": "MIRA — Day 7: The “Stage B” Breakthrough (Multi-Object Detection) The Engineering Change: Scrapping the Foundation Stage A (Classification) was a controlled laboratory success, but it failed the “Real World Test”, and wasnt able to accuractly depict objects with a live cam feed, I also hit a major roadblock: my auto-labeling script used Canny Edge detection which, due to table glare and shadows, mistook my entire desk for a single object. This taught me the most important lesson in AI: Garbage In, Garbage Out (GIGO). To save MIRA, I had to delete my original dataset and move to a professional Object Detection architecture ( YOLOv8-Nano ). Data Engineering: Mapping 64 Classes to 5 I forked a high-variance “Wild Trash” dataset containing thousands of images of waste in complex environments (grass, dirt, water). The Problem: The dataset had 64 highly specific classes (e.g., “Aerosol,” “Egg carton,” “Plastic lid”). The Solution: I wrote a custom Class Remapping Engine in Python. This script programmatically rewrote thousands of .txt label files, collapsing 64 sub-categories into MIRA’s 5 core functional classes: Glass , Metal , Paper , Plastic , and Trash . Result: A robust, “Super-Dataset” of ~3,300 images ready for spatial training. Cloud-Accelerated Training Training an object detector on a local CPU would have taken days. I migrated the pipeline to Google Colab , utilizing an NVIDIA Tesla T4 GPU . Strategy: I implemented a patience=0 strategy and tuned the learning rate to 1e-3 to force the model to converge over 100 epochs despite the high variance of the “Wild” data. Outcome: Achieved an mAP50 of 82.3% on the combined dataset. The “Nano” architecture was chosen specifically to ensure the final weights (approx 6MB) can run standalone on a Raspberry Pi. The Live Multi-Object Tracking Engine The most exciting part is the new live_detection.py . MIRA no longer just “names” an image; it locates and tracks items in 3D space. ByteTrack Integration: I enabled the ByteTrack algorithm ( persist=True ). Now, the AI assigns a unique ID to every object. If a bottle is briefly covered by a hand, the Kalman Filter “remembers” its position, preventing the future servos for the robot from jittering. Performance: Latency: ~40ms (Inference) Throughput: ~15.6 FPS Simultaneous Detection: Successfully tested with 3+ materials in the frame at once. Diagnostic: Identifying Edge Cases Testing today revealed a specific weakness: Metal cans in vertical orientation (opening facing the camera). Because the feature profile changes from a cylinder to a dark circle, detection confidence drops. Fix Strategy: I will supplement the dataset with ~50 manual “end-on” photos of cans to patch this “Canonical View Bias” before the hardware build. What’s Next Creating a dashboard to see everything regarding the AI and trying to quantize it further this was highly aided by AI this time as I just couldnt fix and needed AI help to fix it. Just wanted to check how big my folder is and its 17.3 GB i really need to clean it up I still have alot failed experiements and private data inside"}, {"post_id": 20882, "ts": "2026-07-02T16:34:53Z", "hours": 0.9542, "text": "MIRA — Day 6: Post-Training Quantization and Signal Smoothing What I Built Today Today I achieved major optimization milestones, Finally creating the INT8 Quantizatio Post-Training INT8 Quantization I implemented src/quantize.py using TensorFlow’s TFLiteConverter . The script center-crops and resizes 100 representative images from the dataset to dynamically calibrate activation ranges, converting the uncompressed Keras model to full 8-bit integer precision. Compression Summary: Keras Full Model: 23.48 MB Standard TFLite: 8.49 MB Quantized INT8 TFLite: 2.61 MB (9.0x smaller than Keras binary) Zero-Dependency Live TFLite Inference I completely created the live webcam inference stream ( src/live_inference_tflite.py ). By implementing a standard mathematical Softmax and image scaling pipeline in pure NumPy, the script now starts instantly and runs with minimal CPU overhead. Jitter Reduction via Exponential Moving Average (EMA) To prevent erratic jumps in presicion so it jumping from 60 to 70 in a second caused by camera focus and exposure changes, I implemented a temporal smoothing filter on the output probabilities: smoothed_probs = alpha * raw_probs + ( 1 - alpha ) * smoothed_probs Furture plans So after thinking about it I found 2 logical problems in my model. FIrst of all the dataset it trained on is still to limited and there is not enough variaton in objects. Secondly the whole Infracstructer is wrong and at the moment its classifier and not a detecter so Its nor able to detect mutipile objects which is important for the Robot arm its also not able to discern mutipile objects on the same screen. So the next Part will porbally be a long post in which I fix all these bugs and add New featurs"}, {"post_id": 20127, "ts": "2026-07-01T17:32:54Z", "hours": 1.4083, "text": "MIRA — Day 5: Transfer Learning, and Two-Stage Fine-Tuning 1. Summary Since the last update, which was quite a while ago because I needed to learn some more basics, MIRA has evolved. By implementing transfer learning with MobileNetV2, and performing partial layer fine-tuning, overall validation accuracy was raised from 61% to 87.42% , while validation loss dropped from 1.06 to 0.31 . Which is very important. 3. Key Technical Breakthroughs & Refactors The “Paper” Class Feature Extraction Bottleneck In the initial baseline model, paper recall was extremely poor (0.07). The model regularly confused paper with metal or plastic. The Fix: Using the pre-trained ImageNet weights of MobileNetV2 resolved this. The model now extracts high-level semantic texture and edge properties. In EXP-003, paper reached a 96% precision rate . but instead metal got a bit worse and has now reached 77% from its orignal 86% Refactoring src/evaluate.py To prevent difficulties in strcuturing and avoid having multiple different evaluation scripts for each model , I refactored evaluate.py using Python’s argparse library. The script now accepts command-line arguments to evaluate any model dynamically so i can just use a comand and where it should save its finding and it will run the script acording to that: python src/evaluate.py --model mira_fine_tuned_model.keras --exp EXP-003_FineTuning It also dynamically scales the loaded image resolution (224x224 for MobileNetV2 vs. 180x180 for baseline) to avoid input shape mismatches Implementation of Two-Stage Fine-Tuning After training the custom dense classification head on frozen MobileNetV2 features, I wrote train_fine_tune.py to unfreeze the base model from layer 100 onwards (leaving the low-level edge-detection layers 0–99 intact). Recompiling with an ultra-low learning rate ( 1e-5 ) allowed the model to subtly adjust its deep weights to the recycling dataset: This successfully drove validation loss down to 0.3148 , showing that the network is making predictions with significantly higher statistical confidence. Automated Latency Benchmarking I integrated CPU latency tracking directly into the evaluation loop using time.perf_counter() to record inference times in milliseconds per image, This will be used later to see how it performs on small hardware and different I would advise everybody who wants to do something similar to use the resources i linked. 4. Next Milestones Real-time Live Webcam Inference ( src/live_inference.py ): Deploying the mira_fine_tuned_model.keras on a live video stream to evaluate performance and classification stability under varying lighting and structural angles and add these kinds of borders which state what the computer thinks the object i show is Embedded Planning: Utilising INT8 to quantize the model to a fracture of its size to run on a standalone, onboard single-board computer (Raspberry Pi), moving closer to an autonomous physical robot. Which will then be able to automatically sort them. 5. Resources Used Framework Foundation: TensorFlow Image Classification Tutorial Data Pipelines: TensorFlow image_dataset_from_directory API Model Composition: Keras Sequential Model Documentation Conceptual Architecture: 3Blue1Brown Neural Networks Playlist —"}, {"post_id": 16982, "ts": "2026-06-27T15:48:50Z", "hours": 0.9189, "text": "MIRA — Day 4: Evaluate and important results What I Built Today I built evaluate.py and redid all of my images so my data and captured 800 increasing the count from 120 to 800. This allows me to load my 800-image dataset, evaluate it against a validation set, and output a visual Confusion Matrix. Vital Changes & Difficulties Faced 1. The Alphabet-Slice Bug (Deterministic Split vs. Batch Shuffling) When I first ran evaluate.py , my Confusion Matrix looked bizarre: I had 159 test files, but every single one of them had a true label of “plastic” ! To keep my evaluation predictions aligned with the correct labels, I had initially set shuffle=False when loading the directory. Because Keras loads folders alphabetically ( glass -> metal -> paper -> plastic ), disabling shuffling caused it to read the sorted list and simply slice the last 20% for testing. The last 20% of the alphabet was entirely plastic . To fix this, I set shuffle=True so Keras would pull the exact same random validation split as the training script. To prevent the predictions from getting mismatched during shuffling, I refactored the evaluation script to pull images and labels simultaneously, batch-by-batch: y_true = [] y_pred = [] for images , labels in val_ds : preds = model . predict ( images , verbose = 0 ) batch_preds = np . argmax ( preds , axis = 1 ) y_pred . extend ( batch_preds ) y_true . extend ( labels . numpy ()) No matter how randomly Keras shuffles the images, our answers and guesses are extracted at the exact same instant, making mismatching impossible. The Paper vs. Metal Crisis 📊 With the pipeline corrected, I ran the evaluation and got a real, stable baseline accuracy of 61% worse than yestarday which was expected as the images were alot more than before and before them it was just learning the images and not guessing. Across my 159 validation images. The Confusion Matrix revealed a major failure point in my baseline CNN: True Paper Images: 42 Correctly classified as Paper: 3 Misclassified as Metal: 25 (59.5%) My simple 3-layer CNN is nearly blind to paper textures. It looks at white paper or cardboard with bright reflections and thinks: “Ah, a bright shiny reflection! This must be a metal can.” What’s Next Now that I have documented my true baseline and identified its major blind spot, we are ready to implement Transfer Learning (MobileNetV2) . This pre-trained model has seen millions of images and knows how to distinguish between the flat texture of paper/cardboard and the metallic shine of aluminum. Also i noticed that I struggled quite alot with this part so iam going to pause this project a bit to do another project ot solidify my python basics and continue from there onwards. Resources & Documentation Keras Sequential Model API — Documentation used to structure layers, dropout, and data augmentation. Scikit-Learn Classification Report — Reference for evaluating precision and recall. Scikit-Learn Confusion Matrix Display — Documentation used to plot the final matrix."}, {"post_id": 16440, "ts": "2026-06-26T19:11:19Z", "hours": 1.3836, "text": "MIRA — Day 3 Creating Model and training on Limited data What I Built Today Today I built train_baseline.py , the first complete CNN training pipeline for MIRA. The script loads the dataset, applies data augmentation, trains a 3-layer convolutional neural network, plots the accuracy and loss curves, and saves the trained model to disk. I followed the official TensorFlow image classification tutorial and adjusted it to fit the MIRA dataset structure and 4-class recycling problem. model = Sequential ([ data_augmentation , layers . Rescaling ( 1. / 255 ), layers . Conv2D ( 16 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Conv2D ( 32 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Conv2D ( 64 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Dropout ( 0.2 ), layers . Flatten (), layers . Dense ( 128 , activation = ' relu ' ), layers . Dense ( num_classes , name = \" outputs \" ) ]) Difficulty: Image Stretching The first training run loaded images incorrectly, the model was receiving stretched and distorted frames because image_dataset_from_directory resizes images to the target dimensions by default, squashing non-square images. Fixed by adding crop_to_aspect_ratio=True , which crops from the center instead of stretching: train_ds = tf . keras . utils . image_dataset_from_directory ( data_dir , validation_split = 0.2 , subset = \" training \" , seed = 123 , image_size = ( img_height , img_width ), batch_size = batch_size , crop_to_aspect_ratio = True ) Difficulty: Overfitting Early runs showed training accuracy climbing while validation accuracy stayed flat or dropped ,the model was memorizing the training images rather than learning generalizable features. This happens when the dataset is too small relative to the model’s capacity. Fixed with two countermeasures: data augmentation (RandomFlip, RandomRotation, RandomZoom) to artificially vary the training images, and Dropout(0.2) to prevent individual neurons from becoming too specialized. Results val_acc = 0.8235 @ epoch 20 val_loss = 0.4030 @ epoch 20 best val_acc = 0.8824 @ epoch 19 best val_loss = 0.3646 @ epoch 19 dataset = 126 images / 4 classes The high epoch-to-epoch variance in validation accuracy (swings of ±18%) is happening because of the low validation set containing only 17 images, one wrong prediction equals a 5.9% accuracy shift. Results will stabilize further after expanding the dataset. Coming from C/C++ Well nothing to say because I never coded anything like this in C/C++ so this one will be the last Coming from C/C++ What’s Next I will capture 200 images per class (800 total). So my results are actually meaningful and verfiable also in the images I will adjust lighning and more After the dataset is large enough: I will Write evaluate.py , load the saved model, run it on the test set, and compute a full classification report: precision, recall, and F1-score per class. So I get a per class breakdown of the real acuraccy of the certain folder each and not just the total median. Resources Used TensorFlow image classification tutorial TensorFlow image_dataset_from_directory API Keras Sequential model API 3Blue1Brown — Neural Networks series Credits Also wanted to shoutout RUMI where i got insperation for the naming scheme from."}, {"post_id": 16264, "ts": "2026-06-26T13:29:50Z", "hours": 0.9311, "text": "MIRA — Day 3 visualise data set What I Built Today Today I wrote visualize_dataset.py from scratch using the Python os , random , and Matplotlib documentation. The script counts images per class folder, samples up to 5 random images per class, and displays them in a labeled 4×5 grid. This is a sanity check before the model training you cannot train reliably on a dataset you have never inspected. import os import random import cv2 import matplotlib.pyplot as plt DATA_DIR = \" ../data/ \" CLASSES = [ ' glass ' , ' metal ' , ' paper ' , ' plastic ' ] SAMPLES = 5 total_files = 0 for class_name in CLASSES : folder = os . path . join ( DATA_DIR , class_name ) num_files = len ([ f for f in os . listdir ( folder ) if f . lower (). endswith (( ' .jpg ' , ' .jpeg ' , ' .png ' ))]) print ( f \" { class_name : < 10 } : { num_files } images \" ) total_files += num_files print ( f \" { ' Total ' : < 10 } : { total_files } images \" ) fig , axes = plt . subplots ( len ( CLASSES ), SAMPLES , figsize = ( 15 , 10 )) for row , class_name in enumerate ( CLASSES ): folder = os . path . join ( DATA_DIR , class_name ) files = [ f for f in os . listdir ( folder ) if f . lower (). endswith (( ' .jpg ' , ' .jpeg ' , ' .png ' ))] sampled = random . sample ( files , min ( SAMPLES , len ( files ))) for col , filename in enumerate ( sampled ): img = cv2 . imread ( os . path . join ( folder , filename )) img = cv2 . cvtColor ( img , cv2 . COLOR_BGR2RGB ) axes [ row , col ]. imshow ( img ) axes [ row , col ]. axis ( ' off ' ) if col == 0 : axes [ row , col ]. set_ylabel ( class_name , fontsize = 12 ) plt . tight_layout () plt . show () How It Works The script has two distinct parts. First, the counter loop iterates over each class folder using os.listdir() , filters for image file extensions, and accumulates a total. Second, the grid section uses plt.subplots() to create a fixed axes array indexed by axes[row, col] , each cell addressed independently by class row and sample column. random.sample(files, min(SAMPLES, len(files))) guards against crashes when a folder has fewer than 5 images by capping k to whatever is available. So if I only got three it just going to use three and not crash like it would normaly do for this part I ran my Code through ki afterwards and he told me to add it The one conversion that matters: cv2.cvtColor(img, cv2.COLOR_BGR2RGB) before passing to Matplotlib. OpenCV loads images in BGR channel order; Matplotlib expects RGB. Without this, all reds appear blue. I forgot this but when the pictures came out weird i remeberd the tutorial by Tech with Tim where he mentions it mutipile times I would advise everybody to watch his openCV turorial Difficulty Straightforward session. Coming from C/C++, the structure of iterating over a list of strings and using them as both display labels and filesystem paths felt natural immediately. plt.subplots() returning a 2D array of axes objects is the same concept as a 2D array in C — index by row and column. No significant blockers. Resources used: Matplotlib docs: pyplot.subplots , pyplot.imshow , Axes.set_ylabel Python docs: os.path.join , os.listdir OpenCV docs: cvtColor color conversion codes Dataset Status glass : 32 images metal : 31 images paper : 30 images plastic : 33 images Total : 126 images Also all this images are not in the Github at the moment because these aren’t high quality and good images on which i can train my model What’s Next Dataset is captured and verified. Next is the first CNN training pipeline in TensorFlow/Keras, train_baseline.py . This means learning ml and taking my first steps into it . The target for the first run is a accuracy above 75%."}, {"post_id": 15842, "ts": "2026-06-25T19:17:33Z", "hours": 2.1517, "text": "MIRA — Day 2: Dataset Capture Pipeline What I Built Wrote capture_frame.py from scratch using only the OpenCV docs, no tutorials for the code, no AI-generated code. The script opens a live webcam feed and lets me build my own labeled image dataset by pressing keystroke shortcuts to save frames directly into categorized folders. Evolution of the Capture Logic In my first draft, I managed file naming with a manual integer counter. It worked, but had a critical flaw: every time the script restarted, the counter reset to 1 and began overwriting existing files. Also through out this project I have always specified the Data type because i got advice from a friend to do that. Initial counter approach: i = int ( 1 ) if key == ord ( ' 1 ' ): filepath = os . path . join ( glass_folder , f ' frame_ { i } .jpg ' ) cv2 . imwrite ( filepath , frame ) i += 1 I replaced this with timestamp-based naming using datetime.now().strftime(\"%Y%m%d_%H%M%S\") , which ensures every file has a unique name regardless of how many times the script restarts: glass_20260625_143022.jpg glass_20260625_143022.jpg Make it more efficent to scale My first working draft had four separate folder variables and a long if/elif chain, one block per material class. Functional, but not scalable because this would mean: adding a fifth class would mean copy-pasting another entire block. First draft, repetitive structure: glass_folder = \" ../data/glass/ \" metal_folder = \" ../data/metal/ \" if key == ord ( ' 1 ' ): filepath = os . path . join ( glass_folder , f ' glass_ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) elif key == ord ( ' 2 ' ): filepath = os . path . join ( metal_folder , f ' metal_ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) Refactored: CLASSES = { ' 1 ' : ( ' glass ' , ' ../data/glass/ ' ), ' 2 ' : ( ' metal ' , ' ../data/metal/ ' ), } key_char = chr ( key ) if key_char in CLASSES : label , folder = CLASSES [ key_char ] filepath = os . path . join ( folder , f ' { label } _ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) Adding a fifth class now takes one line in the dictionary. The save logic doesn’t change at all which is pretty neat this was quite difficult because I never worked with classes like this but I managed to do it after googling and asking AI how to set up Classes but not providing it any context so I can write it myself. Coming from C/C++ One thing I found difficult to utilise where f strings. I dont know if a equalivent exists in C/C++ but I never used it so it was quite weird utilising them but they’re very convient and this is another positive aspect of the high abstraction. What’s Next The dataset capture pipeline is working. Next session I will write visualize_dataset.py , a script that loads random samples from each class folder, displays them in a grid, and prints the class distribution as a count per folder. This will then be the basis for my CNN pipelane Resources & Documentation OpenCV 4.x Documentation Python Datetime Guide OS Path Management Tech With Tim - OpenCV Python Tutorial Video 3"}, {"post_id": 15216, "ts": "2026-06-24T18:39:47Z", "hours": 2.0128, "text": "MIRA Project - Architecture & Infrastructure Work Completed: Initialized project architecture and created the virtual environment ( .venv ). Structerd the directory ( data/glass , data/metal , data/paper , data/plastic ) in preparation for supervised machine learning pipelines. Wrote and executed a system boot script to test Python and terminal output. Which just utilises time.sleep() and print() . linked the local workspace to GitHub and pushed the first commit. Studied Python syntax, focusing on loops, variables, and type hinting, easy cause I alredy got basics from other languages. Next Step: Studying OpenCV documentation and computer vision fundamentals to create without using AI capture_frame.py . The goal is to build an automated dataset generation script where a keystroke triggers webcam capture and pushes the image directly to the designated categorization folder So i can just make my data set generation easier or maybe I am going to use a public one iam still undecided. Reflection: Python vs. C/C++ The logic of Python is simple, but adjusting to the syntax is quite weird. Coming from lower-level languages that require strict structuring (like C/C++), the “freedom” and abstraction of Python takes some getting used to. First of all, the absence of semicolons ( ; ) to terminate lines and the reliance on indentation for loops and functions feels unusual. However, the freedom makes certain things simpler. For example, Python’s for loops : names : list [ str ] = [ ' Alice ' , ' Bob ' , ' Charlie ' , ' Anni-Frid ' ] for name in names : print ( f ' Hello, { name } ' ) In C, you have to manually manage the loop counter and the array index, which overcomplicates a simple process: for ( int i = 0 ; i < 4 ; i ++ ) { printf ( \"Hello, %s \\n \" , names [ i ]); } Conclusion For a moment I wasn’t sure if this would really be possible but I gained a lot more confidince through learning a bit and I think this will probally be a long term Project because of the Scale and future stuff I have in mind."}]...
|
Title: MIRA - Machine Intelligence for Recycling b Title: MIRA - Machine Intelligence for Recycling by @jeremy | Stardance
Devlogs:
MIRA Project - Architecture & Infrastructure Work Completed: Initialized project architecture and created the virtual environment ( .venv ). Structerd the directory ( data/glass , data/metal , data/paper , data/plastic ) in preparation for supervised machine learning pipelines. Wrote and executed a system boot script to test Python and terminal output. Which just utilises time.sleep() and print() . linked the local workspace to GitHub and pushed the first commit. Studied Python syntax, focusing on loops, variables, and type hinting, easy cause I alredy got basics from other languages. Next Step: Studying OpenCV documentation and computer vision fundamentals to create without using AI capture_frame.py . The goal is to build an automated dataset generation script where a keystroke triggers webcam capture and pushes the image directly to the designated categorization folder So i can just make my data set generation easier or maybe I am going to use a public one iam still undecided. Reflection: Python vs. C/C++ The logic of Python is simple, but adjusting to the syntax is quite weird. Coming from lower-level languages that require strict structuring (like C/C++), the “freedom” and abstraction of Python takes some getting used to. First of all, the absence of semicolons ( ; ) to terminate lines and the reliance on indentation for loops and functions feels unusual. However, the freedom makes certain things simpler. For example, Python’s for loops : names : list [ str ] = [ ' Alice ' , ' Bob ' , ' Charlie ' , ' Anni-Frid ' ] for name in names : print ( f ' Hello, { name } ' ) In C, you have to manually manage the loop counter and the array index, which overcomplicates a simple process: for ( int i = 0 ; i < 4 ; i ++ ) { printf ( "Hello, %s \n " , names [ i ]); } Conclusion For a moment I wasn’t sure if this would really be possible but I gained a lot more confidince through learning a bit and I think this will probally be a long term Project because of the Scale and future stuff I have in mind.
MIRA — Day 2: Dataset Capture Pipeline What I Built Wrote capture_frame.py from scratch using only the OpenCV docs, no tutorials for the code, no AI-generated code. The script opens a live webcam feed and lets me build my own labeled image dataset by pressing keystroke shortcuts to save frames directly into categorized folders. Evolution of the Capture Logic In my first draft, I managed file naming with a manual integer counter. It worked, but had a critical flaw: every time the script restarted, the counter reset to 1 and began overwriting existing files. Also through out this project I have always specified the Data type because i got advice from a friend to do that. Initial counter approach: i = int ( 1 ) if key == ord ( ' 1 ' ): filepath = os . path . join ( glass_folder , f ' frame_ { i } .jpg ' ) cv2 . imwrite ( filepath , frame ) i += 1 I replaced this with timestamp-based naming using datetime.now().strftime("%Y%m%d_%H%M%S") , which ensures every file has a unique name regardless of how many times the script restarts: glass_20260625_143022.jpg glass_20260625_143022.jpg Make it more efficent to scale My first working draft had four separate folder variables and a long if/elif chain, one block per material class. Functional, but not scalable because this would mean: adding a fifth class would mean copy-pasting another entire block. First draft, repetitive structure: glass_folder = " ../data/glass/ " metal_folder = " ../data/metal/ " if key == ord ( ' 1 ' ): filepath = os . path . join ( glass_folder , f ' glass_ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) elif key == ord ( ' 2 ' ): filepath = os . path . join ( metal_folder , f ' metal_ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) Refactored: CLASSES = { ' 1 ' : ( ' glass ' , ' ../data/glass/ ' ), ' 2 ' : ( ' metal ' , ' ../data/metal/ ' ), } key_char = chr ( key ) if key_char in CLASSES : label , folder = CLASSES [ key_char ] filepath = os . path . join ( folder , f ' { label } _ { timestamp } .jpg ' ) cv2 . imwrite ( filepath , frame ) Adding a fifth class now takes one line in the dictionary. The save logic doesn’t change at all which is pretty neat this was quite difficult because I never worked with classes like this but I managed to do it after googling and asking AI how to set up Classes but not providing it any context so I can write it myself. Coming from C/C++ One thing I found difficult to utilise where f strings. I dont know if a equalivent exists in C/C++ but I never used it so it was quite weird utilising them but they’re very convient and this is another positive aspect of the high abstraction. What’s Next The dataset capture pipeline is working. Next session I will write visualize_dataset.py , a script that loads random samples from each class folder, displays them in a grid, and prints the class distribution as a count per folder. This will then be the basis for my CNN pipelane Resources & Documentation OpenCV 4.x Documentation Python Datetime Guide OS Path Management Tech With Tim - OpenCV Python Tutorial Video 3
MIRA — Day 3 visualise data set What I Built Today Today I wrote visualize_dataset.py from scratch using the Python os , random , and Matplotlib documentation. The script counts images per class folder, samples up to 5 random images per class, and displays them in a labeled 4×5 grid. This is a sanity check before the model training you cannot train reliably on a dataset you have never inspected. import os import random import cv2 import matplotlib.pyplot as plt DATA_DIR = " ../data/ " CLASSES = [ ' glass ' , ' metal ' , ' paper ' , ' plastic ' ] SAMPLES = 5 total_files = 0 for class_name in CLASSES : folder = os . path . join ( DATA_DIR , class_name ) num_files = len ([ f for f in os . listdir ( folder ) if f . lower (). endswith (( ' .jpg ' , ' .jpeg ' , ' .png ' ))]) print ( f " { class_name : < 10 } : { num_files } images " ) total_files += num_files print ( f " { ' Total ' : < 10 } : { total_files } images " ) fig , axes = plt . subplots ( len ( CLASSES ), SAMPLES , figsize = ( 15 , 10 )) for row , class_name in enumerate ( CLASSES ): folder = os . path . join ( DATA_DIR , class_name ) files = [ f for f in os . listdir ( folder ) if f . lower (). endswith (( ' .jpg ' , ' .jpeg ' , ' .png ' ))] sampled = random . sample ( files , min ( SAMPLES , len ( files ))) for col , filename in enumerate ( sampled ): img = cv2 . imread ( os . path . join ( folder , filename )) img = cv2 . cvtColor ( img , cv2 . COLOR_BGR2RGB ) axes [ row , col ]. imshow ( img ) axes [ row , col ]. axis ( ' off ' ) if col == 0 : axes [ row , col ]. set_ylabel ( class_name , fontsize = 12 ) plt . tight_layout () plt . show () How It Works The script has two distinct parts. First, the counter loop iterates over each class folder using os.listdir() , filters for image file extensions, and accumulates a total. Second, the grid section uses plt.subplots() to create a fixed axes array indexed by axes[row, col] , each cell addressed independently by class row and sample column. random.sample(files, min(SAMPLES, len(files))) guards against crashes when a folder has fewer than 5 images by capping k to whatever is available. So if I only got three it just going to use three and not crash like it would normaly do for this part I ran my Code through ki afterwards and he told me to add it The one conversion that matters: cv2.cvtColor(img, cv2.COLOR_BGR2RGB) before passing to Matplotlib. OpenCV loads images in BGR channel order; Matplotlib expects RGB. Without this, all reds appear blue. I forgot this but when the pictures came out weird i remeberd the tutorial by Tech with Tim where he mentions it mutipile times I would advise everybody to watch his openCV turorial Difficulty Straightforward session. Coming from C/C++, the structure of iterating over a list of strings and using them as both display labels and filesystem paths felt natural immediately. plt.subplots() returning a 2D array of axes objects is the same concept as a 2D array in C — index by row and column. No significant blockers. Resources used: Matplotlib docs: pyplot.subplots , pyplot.imshow , Axes.set_ylabel Python docs: os.path.join , os.listdir OpenCV docs: cvtColor color conversion codes Dataset Status glass : 32 images metal : 31 images paper : 30 images plastic : 33 images Total : 126 images Also all this images are not in the Github at the moment because these aren’t high quality and good images on which i can train my model What’s Next Dataset is captured and verified. Next is the first CNN training pipeline in TensorFlow/Keras, train_baseline.py . This means learning ml and taking my first steps into it . The target for the first run is a accuracy above 75%.
MIRA — Day 3 Creating Model and training on Limited data What I Built Today Today I built train_baseline.py , the first complete CNN training pipeline for MIRA. The script loads the dataset, applies data augmentation, trains a 3-layer convolutional neural network, plots the accuracy and loss curves, and saves the trained model to disk. I followed the official TensorFlow image classification tutorial and adjusted it to fit the MIRA dataset structure and 4-class recycling problem. model = Sequential ([ data_augmentation , layers . Rescaling ( 1. / 255 ), layers . Conv2D ( 16 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Conv2D ( 32 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Conv2D ( 64 , 3 , padding = ' same ' , activation = ' relu ' ), layers . MaxPooling2D (), layers . Dropout ( 0.2 ), layers . Flatten (), layers . Dense ( 128 , activation = ' relu ' ), layers . Dense ( num_classes , name = " outputs " ) ]) Difficulty: Image Stretching The first training run loaded images incorrectly, the model was receiving stretched and distorted frames because image_dataset_from_directory resizes images to the target dimensions by default, squashing non-square images. Fixed by adding crop_to_aspect_ratio=True , which crops from the center instead of stretching: train_ds = tf . keras . utils . image_dataset_from_directory ( data_dir , validation_split = 0.2 , subset = " training " , seed = 123 , image_size = ( img_height , img_width ), batch_size = batch_size , crop_to_aspect_ratio = True ) Difficulty: Overfitting Early runs showed training accuracy climbing while validation accuracy stayed flat or dropped ,the model was memorizing the training images rather than learning generalizable features. This happens when the dataset is too small relative to the model’s capacity. Fixed with two countermeasures: data augmentation (RandomFlip, RandomRotation, RandomZoom) to artificially vary the training images, and Dropout(0.2) to prevent individual neurons from becoming too specialized. Results val_acc = 0.8235 @ epoch 20 val_loss = 0.4030 @ epoch 20 best val_acc = 0.8824 @ epoch 19 best val_loss = 0.3646 @ epoch 19 dataset = 126 images / 4 classes The high epoch-to-epoch variance in validation accuracy (swings of ±18%) is happening because of the low validation set containing only 17 images, one wrong prediction equals a 5.9% accuracy shift. Results will stabilize further after expanding the dataset. Coming from C/C++ Well nothing to say because I never coded anything like this in C/C++ so this one will be the last Coming from C/C++ What’s Next I will capture 200 images per class (800 total). So my results are actually meaningful and verfiable also in the images I will adjust lighning and more After the dataset is large enough: I will Write evaluate.py , load the saved model, run it on the test set, and compute a full classification report: precision, recall, and F1-score per class. So I get a per class breakdown of the real acuraccy of the certain folder each and not just the total median. Resources Used TensorFlow image classification tutorial TensorFlow image_dataset_from_directory API Keras Sequential model API 3Blue1Brown — Neural Networks series Credits Also wanted to shoutout RUMI where i got insperation for the naming scheme from.
MIRA — Day 4: Evaluate and important results What I Built Today I built evaluate.py and redid all of my images so my data and captured 800 increasing the count from 120 to 800. This allows me to load my 800-image dataset, evaluate it against a validation set, and output a visual Confusion Matrix. Vital Changes & Difficulties Faced 1. The Alphabet-Slice Bug (Deterministic Split vs. Batch Shuffling) When I first ran evaluate.py , my Confusion Matrix looked bizarre: I had 159 test files, but every single one of them had a true label of “plastic” ! To keep my evaluation predictions aligned with the correct labels, I had initially set shuffle=False when loading the directory. Because Keras loads folders alphabetically ( glass -> metal -> paper -> plastic ), disabling shuffling caused it to read the sorted list and simply slice the last 20% for testing. The last 20% of the alphabet was entirely plastic . To fix this, I set shuffle=True so Keras would pull the exact same random validation split as the training script. To prevent the predictions from getting mismatched during shuffling, I refactored the evaluation script to pull images and labels simultaneously, batch-by-batch: y_true = [] y_pred = [] for images , labels in val_ds : preds = model . predict ( images , verbose = 0 ) batch_preds = np . argmax ( preds , axis = 1 ) y_pred . extend ( batch_preds ) y_true . extend ( labels . numpy ()) No matter how randomly Keras shuffles the images, our answers and guesses are extracted at the exact same instant, making mismatching impossible. The Paper vs. Metal Crisis 📊 With the pipeline corrected, I ran the evaluation and got a real, stable baseline accuracy of 61% worse than yestarday which was expected as the images were alot more than before and before them it was just learning the images and not guessing. Across my 159 validation images. The Confusion Matrix revealed a major failure point in my baseline CNN: True Paper Images: 42 Correctly classified as Paper: 3 Misclassified as Metal: 25 (59.5%) My simple 3-layer CNN is nearly blind to paper textures. It looks at white paper or cardboard with bright reflections and thinks: “Ah, a bright shiny reflection! This must be a metal can.” What’s Next Now that I have documented my true baseline and identified its major blind spot, we are ready to implement Transfer Learning (MobileNetV2) . This pre-trained model has seen millions of images and knows how to distinguish between the flat texture of paper/cardboard and the metallic shine of aluminum. Also i noticed that I struggled quite alot with this part so iam going to pause this project a bit to do another project ot solidify my python basics and continue from there onwards. Resources & Documentation Keras Sequential Model API — Documentation used to structure layers, dropout, and data augmentation. Scikit-Learn Classification Report — Reference for evaluating precision and recall. Scikit-Learn Confusion Matrix Display — Documentation used to plot the final matrix.
MIRA — Day 5: Transfer Learning, and Two-Stage Fine-Tuning 1. Summary Since the last update, which was quite a while ago because I needed to learn some more basics, MIRA has evolved. By implementing transfer learning with MobileNetV2, and performing partial layer fine-tuning, overall validation accuracy was raised from 61% to 87.42% , while validation loss dropped from 1.06 to 0.31 . Which is very important. 3. Key Technical Breakthroughs & Refactors The “Paper” Class Feature Extraction Bottleneck In the initial baseline model, paper recall was extremely poor (0.07). The model regularly confused paper with metal or plastic. The Fix: Using the pre-trained ImageNet weights of MobileNetV2 resolved this. The model now extracts high-level semantic texture and edge properties. In EXP-003, paper reached a 96% precision rate . but instead metal got a bit worse and has now reached 77% from its orignal 86% Refactoring src/evaluate.py To prevent difficulties in strcuturing and avoid having multiple different evaluation scripts for each model , I refactored evaluate.py using Python’s argparse library. The script now accepts command-line arguments to evaluate any model dynamically so i can just use a comand and where it should save its finding and it will run the script acording to that: python src/evaluate.py --model mira_fine_tuned_model.keras --exp EXP-003_FineTuning It also dynamically scales the loaded image resolution (224x224 for MobileNetV2 vs. 180x180 for baseline) to avoid input shape mismatches Implementation of Two-Stage Fine-Tuning After training the custom dense classification head on frozen MobileNetV2 features, I wrote train_fine_tune.py to unfreeze the base model from layer 100 onwards (leaving the low-level edge-detection layers 0–99 intact). Recompiling with an ultra-low learning rate ( 1e-5 ) allowed the model to subtly adjust its deep weights to the recycling dataset: This successfully drove validation loss down to 0.3148 , showing that the network is making predictions with significantly higher statistical confidence. Automated Latency Benchmarking I integrated CPU latency tracking directly into the evaluation loop using time.perf_counter() to record inference times in milliseconds per image, This will be used later to see how it performs on small hardware and different I would advise everybody who wants to do something similar to use the resources i linked. 4. Next Milestones Real-time Live Webcam Inference ( src/live_inference.py ): Deploying the mira_fine_tuned_model.keras on a live video stream to evaluate performance and classification stability under varying lighting and structural angles and add these kinds of borders which state what the computer thinks the object i show is Embedded Planning: Utilising INT8 to quantize the model to a fracture of its size to run on a standalone, onboard single-board computer (Raspberry Pi), moving closer to an autonomous physical robot. Which will then be able to automatically sort them. 5. Resources Used Framework Foundation: TensorFlow Image Classification Tutorial Data Pipelines: TensorFlow image_dataset_from_directory API Model Composition: Keras Sequential Model Documentation Conceptual Architecture: 3Blue1Brown Neural Networks Playlist —
MIRA — Day 6: Post-Training Quantization and Signal Smoothing What I Built Today Today I achieved major optimization milestones, Finally creating the INT8 Quantizatio Post-Training INT8 Quantization I implemented src/quantize.py using TensorFlow’s TFLiteConverter . The script center-crops and resizes 100 representative images from the dataset to dynamically calibrate activation ranges, converting the uncompressed Keras model to full 8-bit integer precision. Compression Summary: Keras Full Model: 23.48 MB Standard TFLite: 8.49 MB Quantized INT8 TFLite: 2.61 MB (9.0x smaller than Keras binary) Zero-Dependency Live TFLite Inference I completely created the live webcam inference stream ( src/live_inference_tflite.py ). By implementing a standard mathematical Softmax and image scaling pipeline in pure NumPy, the script now starts instantly and runs with minimal CPU overhead. Jitter Reduction via Exponential Moving Average (EMA) To prevent erratic jumps in presicion so it jumping from 60 to 70 in a second caused by camera focus and exposure changes, I implemented a temporal smoothing filter on the output probabilities: smoothed_probs = alpha * raw_probs + ( 1 - alpha ) * smoothed_probs Furture plans So after thinking about it I found 2 logical problems in my model. FIrst of all the dataset it trained on is still to limited and there is not enough variaton in objects. Secondly the whole Infracstructer is wrong and at the moment its classifier and not a detecter so Its nor able to detect mutipile objects which is important for the Robot arm its also not able to discern mutipile objects on the same screen. So the next Part will porbally be a long post in which I fix all these bugs and add New featurs
MIRA — Day 7: The “Stage B” Breakthrough (Multi-Object Detection) The Engineering Change: Scrapping the Foundation Stage A (Classification) was a controlled laboratory success, but it failed the “Real World Test”, and wasnt able to accuractly depict objects with a live cam feed, I also hit a major roadblock: my auto-labeling script used Canny Edge detection which, due to table glare and shadows, mistook my entire desk for a single object. This taught me the most important lesson in AI: Garbage In, Garbage Out (GIGO). To save MIRA, I had to delete my original dataset and move to a professional Object Detection architecture ( YOLOv8-Nano ). Data Engineering: Mapping 64 Classes to 5 I forked a high-variance “Wild Trash” dataset containing thousands of images of waste in complex environments (grass, dirt, water). The Problem: The dataset had 64 highly specific classes (e.g., “Aerosol,” “Egg carton,” “Plastic lid”). The Solution: I wrote a custom Class Remapping Engine in Python. This script programmatically rewrote thousands of .txt label files, collapsing 64 sub-categories into MIRA’s 5 core functional classes: Glass , Metal , Paper , Plastic , and Trash . Result: A robust, “Super-Dataset” of ~3,300 images ready for spatial training. Cloud-Accelerated Training Training an object detector on a local CPU would have taken days. I migrated the pipeline to Google Colab , utilizing an NVIDIA Tesla T4 GPU . Strategy: I implemented a patience=0 strategy and tuned the learning rate to 1e-3 to force the model to converge over 100 epochs despite the high variance of the “Wild” data. Outcome: Achieved an mAP50 of 82.3% on the combined dataset. The “Nano” architecture was chosen specifically to ensure the final weights (approx 6MB) can run standalone on a Raspberry Pi. The Live Multi-Object Tracking Engine The most exciting part is the new live_detection.py . MIRA no longer just “names” an image; it locates and tracks items in 3D space. ByteTrack Integration: I enabled the ByteTrack algorithm ( persist=True ). Now, the AI assigns a unique ID to every object. If a bottle is briefly covered by a hand, the Kalman Filter “remembers” its position, preventing the future servos for the robot from jittering. Performance: Latency: ~40ms (Inference) Throughput: ~15.6 FPS Simultaneous Detection: Successfully tested with 3+ materials in the frame at once. Diagnostic: Identifying Edge Cases Testing today revealed a specific weakness: Metal cans in vertical orientation (opening facing the camera). Because the feature profile changes from a cylinder to a dark circle, detection confidence drops. Fix Strategy: I will supplement the dataset with ~50 manual “end-on” photos of cans to patch this “Canonical View Bias” before the hardware build. What’s Next Creating a dashboard to see everything regarding the AI and trying to quantize it further this was highly aided by AI this time as I just couldnt fix and needed AI help to fix it. Just wanted to check how big my folder is and its 17.3 GB i really need to clean it up I still have alot failed experiements and private data inside
MIRA — Day 8: The Invisible Boxes (and Why Two Models Were Lying to Me) BUGS After hours of digging through Ultralytics internals with AI assistance, I found not one but three separate bugs all stacking on top of each other. Bug #1: Tracker Ultralytics 8.4.84 silently switched the default tracker from ByteTrack to something called TRACKTRACK . I never asked for this. Nobody told me. TRACKTRACK has internal confidence thresholds that are absurdly high: track_high_thresh: 0.6 # Only detections >= 0.6 are “real” new_track_thresh: 0.7 # New objects need >= 0.7 to be tracked Here’s the problem: INT8 quantization drops confidence scores by 20-40%. So a detection that would score 0.55 in the original PyTorch model now scores ~0.35 after quantization. TRACKTRACK looks at 0.35, says “too low,” and silently throws it away. No error. No warning. Just… gone. Bug #2: The Double Filter Even if TRACKTRACK somehow kept a box, my drawing function had its own confidence filter set to 0.5. So a box at conf=0.4 that survived the tracker got killed again at the drawing stage. Bug #3: Nothing Stopped the User from Loading the Wrong Model Nothing in the code prevented me from loading mira_classifier_int8.tflite — a classification model — into the detection pipeline. Which i failed to realise. The code just checked if the file ended in .tflite and said “sure, load it as a detector.” It would’ve failed silently or produced garbage. live_detection.py — The Big One I rewrote the core inference loop. Three major changes: Forced ByteTrack everywhere. PyTorch models now explicitly use tracker="bytetrack.yaml" instead of whatever Ultralytics defaults to. No more silent tracker swaps. Bypassed the tracker entirely for INT8 models. TFLite INT8 now uses model.predict() instead of model.track() . No tracker = no threshold filtering = boxes actually appear. Conf is auto-overridden to 0.25 at startup because INT8 models need lower thresholds. Added model validation. If you try to load a classifier model into the detection pipeline, you now get a clear error: ERROR: ‘mira_classifier_int8.tflite’ is a CLASSIFIER model, not a detector. Live detection requires a detection model (.pt or detection .tflite). Use ’mira eval-class –model mira_classifier_int8.tflite –exp ’ instead. No more silent failures. dashboard.py — Same Story, Streamlit Edition The Streamlit dashboard had the exact same tracker and threshold bugs. Fixed identically: ByteTrack forced, INT8 models use predict(), classifier models filtered from the sidebar before you can even select them. cli.py — First Line of Defence Updated cli.py and added mutiple new commands to make it easier to use also made it possible to use in the termnail through a bat file so u can run the scripts in powershell if you want if you just add .\mira and then commands. Also Added validation in the live subcommand so classifier models get rejected before the subprocess even spawns. Faster error, cleaner output. Folder Cleanup Reality Checked the project size today: 17.3 GB. That’s absurd for a recycling classifier. Most of it is: Failed experiment outputs Raw dataset images that should’ve been gitignored Multiple copies of the same model in different formats Private test data that never should’ve been committed Need to do a serious cleanup before pushing anything. What’s Next Downloading three new datasets to retrain on: SortWaste (WACV 2026) — real conveyor belt images, 87k bounding boxes TACO — waste in wild environments (forests, streets, beaches) NAVER Recycle Trash — 21k images, indoor + outdoor Target: Combine everything into ~20,000 images, retrain with YOLO11n, hit 80%+ mAP50 with actual real-world robustness.
MIRA Day 9: YOLO11 Migration, INT8 Issues, and Dataset Analysis Over the last few days, I focused on improving the project structure, simplifying the codebase, and testing different approaches for the detection pipeline. I made around 15 commits, added roughly 2,200 lines of code, and removed around 1,000 lines that were duplicated or no longer needed. The main changes were migrating from YOLOv8n to YOLO11n, creating an automated benchmark script, and investigating why some dataset combinations performed worse than expected. YOLO11 and Dataset Experiments I moved from YOLOv8n to YOLO11n because it is better suited for edge deployment while keeping the model lightweight. Since MIRA is intended to run on limited hardware, inference speed and efficiency are important. To test different training setups, I trained four model variants using Kaggle T4 GPUs. I compared several datasets: TACO: Outdoor litter images. TrashNet: Clean recycling images from controlled environments. Roboflow Trash Detection: Waste images with bounding box annotations. WaRP: Industrial recycling images from conveyor belt environments. The best results came from combining TACO, TrashNet, and Roboflow. This combination performed better during live camera tests because it contained both clean object images and more realistic trash scenarios. Why WaRP Reduced Performance Adding WaRP unexpectedly reduced the performance of my general “Trash” class. The reason was a dataset imbalance. WaRP contains many detailed recycling categories like plastic, glass, metal, and cardboard, but it has very few examples matching my general trash category. After mapping WaRP’s classes into my five target classes, most additional training data was added to recyclable categories. This caused the model to become more focused on plastic, paper, and glass while becoming less reliable at detecting mixed waste. This showed that more training data does not always mean better results. The distribution and relevance of the data are equally important. INT8 Quantization Problem While testing my INT8 TFLite model, I noticed that the detection rate was almost zero. The model itself was working, but my confidence filtering removed valid detections. After INT8 conversion, the output confidence values changed compared to the original model. Some detections that previously passed a 0.50 confidence threshold were now below it. Because my pipeline still used the old threshold, valid detections were discarded. I updated the benchmark and live detector to automatically use a lower confidence threshold for INT8 models. After this change, detections worked correctly again. Code Cleanup and Fixes I found several duplicated parts in the project, especially multiple versions of the bounding box drawing logic. I centralized these functions and cleaned up configuration and path handling. I also fixed two problems in the live detection system: Tracker dependency issue: The detector previously used BoT-SORT by default, which caused problems if the required package was missing. I changed the fallback system to use BYTETrack first. Double confidence filtering: Confidence filtering was happening both during prediction and again during visualization. I moved this into one centralized post-processing step to avoid removing valid detections. Repository Cleanup The project folder has grown to around 17 GB because of duplicated datasets, training results, logs, and model checkpoints. Before pushing everything to GitHub, I need to clean the Git history, improve the .gitignore , and remove unnecessary files. The goal is to reduce the repository size to below 500 MB. Next Steps Clean the repository and remove large unused files. Train the final model with the improved dataset combination. Generate evaluation graphs and confusion matrices for the final documentation.
MIRA — Day 10: Removing Streamlit, Safety, and Purging my LLM Tools I spent the last week cleaning up a massive amount of technical debt. After about 40 commits, touching 168 files, and adding 6,186 lines of code while removing 1,200 lines of old code, the repo is finally much cleaner. The biggest changes were replacing Streamlit with a Flask-SocketIO server, auditing my project for the Jugend Forscht competition, and removing my custom AI development tools (which I built earlier to help me write code). Replacing Streamlit with Flask + SocketIO Streamlit was a bottleneck for real-time video streaming and thread-safe operations because it re-runs the entire script on user interaction. The Architecture: I built a custom Flask and SocketIO dashboard under src/dashboard_flask/ . Live camera frames are captured in a background thread, encoded to JPEG, and pushed over WebSockets. Thread Safety: I implemented four threading locks to prevent race conditions: camera_lock , model_lock , inventory_lock , and config_lock . Bugs Fixed: I resolved an unnecessary BGR-to-RGB conversion that was washing out my live camera colors, and wrapped my configuration updater in config_lock to prevent multi-thread memory corruption. Modularizing my Inference Pipeline To clean up the backend, I consolidated all duplication: I deleted the separate live and debug scripts, merging their logic into a single src/inference_engine.py module. This engine handles the threaded camera feed, YOLO11n prediction loop, and my BYTETrack fallback. All paths, labels, and parameters are now centralized in src/config.py . Purging my Custom AI Tools I built a terminal-based AI coding assistant to help me write and modify code. However, after an architectural review, I decided it does not belong in this repository. The Reason: MIRA stands for Machine Intelligence for Recycling Automation. The codebase should focus strictly on computer vision and robotics, not LLM wrappers. The Separation: I separated all AI coding utilities into a new MIRA-DevTools repository, which I will start as I near the end of MIRA. JUFO Competition Audit & Paper Since this project is for Jugend Forscht, I have been heavily working on my scientific paper (which I realized I haven’t actually mentioned in previous updates). AI Audit: I ran an AI-assisted audit against JUFO evaluation criteria. It originally rated my project at a 6/10 because my paper lacked a deep discussion section and YOLO11n graphs. The Fixes: I expanded my analysis on how the WaRP dataset’s class imbalance skewed my trash predictions, and compiled a 22-page LaTeX report with proper bibliographies and training curves. Quality Assurance: I added 17 unit tests and automated GitHub Actions with Pytest and Ruff. I will translate the paper to English and upload it soon. Next Steps Folder Cleanup: Run git-filter-repo to shrink my 17 GB folder by removing cached datasets before pushing to GitHub. Final Training: Train one last model on my optimized dataset combination once my Kaggle GPU hours reset.
MIRA — Day 11: Dashboard Redesign, Dual Modes, and EXP-017 Datasets Today was all about front-end overhauls and preparation for my next training run. I redesigned my web interface, split it into two dedicated operating modes, and finalized my biggest dataset merge yet to prepare for training EXP-017. Clean Light Theme Dashboard I shifted the entire MIRA web dashboard from my old dark theme to a clean light theme with a mutiple colors. JUFO vs. Stardance Modes I introduced two separate dashboard modes that I can select on-the-fly using URL parameters: JUFO Mode ( ?mode=jufo ): A technical view tailored for competition judges, featuring deep metrics, historical training graphs, and real-time backend diagnostics. Stardance Mode ( ?mode=stardance ): An interactive, simplified playground designed for quick live demonstrations with clean control toggles. System Health & Live Settings I replaced my static history table with a real-time System-Health panel displaying CPU, RAM, temperature, and inference latency using animated progress bars. I also added an “Einstellungen” (Settings) tab to Stardance mode, allowing me to adjust model weights (via a dynamic API model picker), confidence thresholds, IoU, and camera resolution directly from the web UI without needing to restart the Flask backend. Threaded Camera Pipeline My camera stream was bottlenecking my inference engine. I decoupled the frame capture from the detection loop by moving the capture process into a dedicated Python threading.Thread . The web stream now runs at a smooth 20 FPS at 320px resolution. I also patched Camera.release() to verify the stream is open before shutting down, preventing a common camera-close crash. Datasets & EXP-017 Preparation I successfully merged all four of my data sources (TACO, TrashNet, Roboflow, and WaRP) into a unified dataset named mira_all . It contains 9,774 images across 5 classes. While generating the ZIP file, I hit an archive path encoding issue that broke folder hierarchies. I solved this by using just the normal windows option to zip files instead of the powershell way which I wanted to test out My current baseline model (EXP-014) is still performing well with an 85.8% F1-score on my field benchmark, though the general “Trash” class remains my weakest spot at 37.6% due to how much random variation “trash” actually has. Pipline I also worked on pipline and am working on making it plug play allowing user to get any 3rd party model plug it in and use the full research pipline to retrain it compare it benchmark it and do a lot of stuff. I also added the option to add custom datasets and expanded on the CLI with mutiple custom commands this is probally, the second last post because I am nearly finished. The ui for the dashboard was made with ne gpt 5.6 sol because I just couldnt come up with a good ui. Next Steps Train EXP-017: Upload the clean mira_all dataset and run training on Kaggle. Logger Analysis: Review the data from my new last_per_class.json file to see which items are being misidentified during continuous live runs.
MIRA — Day 12: Codebase Audit, EXP-017 Results, and Cross-Platform Fixes Before diving into codebase fixes, I finished training EXP-017 on Kaggle using the merged mira_all dataset. It reached 59.3% mAP50 —which is slightly below EXP-014’s 60.7% . This confirmed a key lesson for me: dataset quality and class balance matter far more than sheer image count. After that, I shifted my focus to running a full diagnostic audit of my codebase to clean up bugs and edge cases. Fixing the Health Check My health check command ( mira doctor ) was crashing immediately on Windows with a UnicodeEncodeError due to special status symbols ( ✓ , ✗ , ⚠ ). I replaced them with plain ASCII characters ( [OK] , [!] , [FAIL] ). Added checks for missing camera backends on Linux so the health check runs cleanly end-to-end regardless of the OS. Making Torch and TensorFlow Optional MIRA supports both PyTorch ( .pt ) and TFLite ( .tflite ) models, but requiring both libraries installed was frustrating—PyTorch alone takes up over 800 MB. I refactored my model adapters and dashboard to use lazy-imports. If PyTorch isn’t installed, PyTorch models gracefully report as unsupported without crashing the application. This allows a lightweight setup without forcing massive unnecessary downloads if someone only wants to run TFLite models on edge hardware. Cross-Platform & Service Hardening I cleaned up my startup scripts and hardened my camera service against common edge-case failures: Updated mira.bat with PYTHONUTF8=1 for Windows, and created a native mira.sh for Linux and macOS. Added OS guards around the Windows-specific DirectShow camera backend. Fixed a potential division-by-zero crash when video FPS drops to zero. Switched Linux CPU temperature reads to psutil instead of hardcoding 0°C. Ensured the model object memory is properly freed on shutdown. Security, Pydantic v2, and Edge Cases Security: I restricted CORS in my web dashboard from wildcard access ( * ) to localhost ( 127.0.0.1:8000 ). Pydantic Upgrade: Replaced deprecated .dict() calls with .model_dump() for Pydantic v2 compatibility. Integrity: Explicitly forced UTF-8 encoding on all YAML file reads, and added SHA-256 hash verification to mira download . Current System Status After resolving these issues, my test suite is sitting at 99 out of 99 passing unit tests , my Ruff linter reports 0 errors , and all 17 CLI commands are fully functional. I also prepared my HackClub StarDance submission writeup and updated the main README with current CLI specs and experiment data. Next Steps Hardware Benchmarking: Measure real-world FPS and inference latency on a Raspberry Pi Zero 2W. Trash Class Data: Collect targeted training images to improve the general “Trash” class, which remains my weakest performer (7.1% mAP50). in this pic you can see a sneakpeak to a new feature
MIRA — Day 13: Backend Bug Cleanup, Test Suite Expansion, and AI Tooling Today was split between fixing silent backend bugs in MIRA-AI, expanding my test suite to 120 passing tests, and configuring my external AI development tools. Backend Bug Cleanup I ran a full diagnostic check across the codebase and resolved 15 specific bugs: Duplicate Camera Service: Found and removed a bug in main.py that was initializing two separate camera service instances on startup. TFLite Tracking Guard: Disabled ByteTrack tracking when running TFLite models in camera_service.py , since TFLite inference doesn’t support ByteTrack tracking. Modern FastAPI Lifecycle: Migrated from deprecated on_event handlers to the modern asynccontextmanager lifespan pattern across my API services. Code Quality: Updated remaining deprecated .dict() calls to .model_dump() for Pydantic v2, fixed an immutable frozenset cleanup bug in my tests, and resolved 183 Ruff linter warnings. Expanding the Test Suite to 120 Tests I wrote new unit test suites for previously uncovered backend modules: Dashboard Models & WebSockets: Added 30+ tests covering Pydantic model serialization and boundary conditions, plus 15+ tests for WebSocket event callbacks and metric queuing. Test Isolation: Fixed a bug in test_logger.py where the root logger was leaking state between test runs, and fixed brittle Python version checks in test_serialization.py . Current Status: My test suite is now sitting at 120 out of 120 passing tests with 0 Ruff lint errors. AI Developer Tooling & DigitalOcean Outside the core MIRA repository, I spent time configuring my external OpenCode AI setup across multiple providers (OpenRouter, local Docker, Ollama, and GitHub Copilot): Fixed an endpoint URL misconfiguration in my OpenRouter settings and tested connectivity across 23 models. Added handling for “reasoning models” that return output in a reasoning field rather than standard content. Researched how to use my $200 DigitalOcean student credit before it expires on July 31st. Since student credits cannot be applied to GPU Droplets, I plan to deploy a 128 GB Memory-Optimized CPU Droplet to run Ollama with 70B models for offloaded testing. Next Steps Hardware Benchmarks: Run real-world FPS and latency tests on a Raspberry Pi Zero 2W. Trash Class Data: Collect targeted training data for the general “Trash” class, which remains my weakest class at 7.1% mAP50. Also go over the website cause it looks pretty ai generated right now
MIRA — Day 14: Dataset Rebuild, Failed Kaggle Runs, and JuFo Preparation Today focused on making MIRA scientifically reliable instead of simply adding more features. I completed another full codebase revamp, checked two failed Kaggle training runs, rebuilt the waste dataset, improved the training workflow, and rewrote the Jugend forscht report. Codebase Audit and Bug Fixing I reviewed the complete Python codebase as about 50% is ai generated and I really didnt take the time to verfiy everything. Important fixes included: Repairing dashboard crashes caused by missing runtime fields and an incorrect performance-metrics function call. Preventing camera shutdown from releasing the camera while another thread was still reading from it. Adding bounded shutdown handling so a blocked camera driver cannot freeze the application. Fixing the custom mAP implementation, which previously allowed predictions from one image to match ground-truth boxes from another image. Preventing export: YAML sections from being passed to Ultralytics as invalid training arguments.. Correcting generated Kaggle and Colab dataset YAML files. Dataset Research and Reconstruction I wanted to train new models so yolo11n and the new yolo26n so I created new datasets. I processed TACO, TrashNet, Roboflow, dmedhi, Keremberke, WaRP, and SortWaste. Keremberke was excluded because its class remapping would have cuased generated approximately 45,000 misleading trash annotations and pushed trash to 40% of all annotation which create an imbalance SortWaste was removed after it showed that most pictures were from the same perspective and always plastic. The rebuilt dataset uses only dmedhi, TACO, Roboflow, and SAM-labeled TrashNet . 5,108 training images 415 tabletop validation images 1,375 independent test images 6,898 unique images 12,832 bounding boxes The training split is approximately balanced, with 1,621–1,982 boxes per class . The final zip is ca 3.6GB Failed Kaggle Training Attempts I ran kaggle scripts overnight and in these was the sortwaste dataset included which gave me these results. Also i did the mistake of running yolo11x and not n whihc explains the 26 epochs even though it ran for 9 hours. YOLO26n 188 epochs 29.1% mAP50 Plastic: 59.7% Trash: 5.4% **YOLO11x ** 26 epochs 20.9% mAP50 Trash: 2.3% These runs were not downloaded or treated as valid results. As they were so bad I didnt want to document them in any kind I ran a new kaggle script for yolo11n with the new cleaned datasets which hopefully has better results. Jugend forscht Report Revision I checked the LaTeX report against the official Jugend forscht requirements. The previous version exceeded the page limit and was quite frankly just bad and build on a lot of assumption so a big part of today was just rewriting it Next Steps I am currently waiting for the YOLO11n training results. The YOLO26n run is planned for next week, as the failed training attempts exhausted my available Kaggle usage. Afterwards, I will benchmark the final model on the Raspberry Pi Zero 2 W I ordered through Stardance. Once the edge-hardware evaluation is complete, I can finalize MIRA and begin planning and building the robot arm.
MIRA — Day 15: Repository Cleanup, EXP-019, and Reproducible Results This time Instead of adding more features, I concentrated on making the existing software easier to understand, easier to reproduce, and just better overall. The main outcomes were a big repo cleanup, New kaggle results with EXP018/019 reaching all time high of mAP50 of 90% Repository Cleanup and Reliability Improvements I performed another detailed check of the complete codebase. Which highlightes some more issues as a lot of code was Ai generated. The review uncovered problems in both the runtime software and the research CLI/pipeline. I cleaned up third party model files, duplicate documentation, archived ZIP files, and unused assets such as Datasets. The local repo had previously grown to ca 13 GB , largely because of old Git objects. After the cleanup, it was reduced to approximately 520 MB . The README was reduced from roughly ** 900 lines** to approximately 340 lines . It now concentrates on the current installation process, the active perception pipeline, the best available models, dataset origins, known limitations, and reproducibility. Jugend forscht material was moved into the jufo/ directory, while the related-work section was separated into its own document and was put in gitignore for various reasons. EXP-018 and EXP-019 After rebuilding the dataset and correcting the training workflow, I trained YOLO11n on the cleaned and balanced dataset. EXP-018 achieved the following results: Metric Result mAP50 90.6% mAP50-95 82.2% Glass mAP50 90.8% Metal mAP50 94.8% Paper mAP50 88.7% Plastic mAP50 81.1% Trash mAP50 97.5% Compared with EXP-014, which achieved 60.7% mAP50 on the older dataset, this represents an improvement of 29.9 percentage points . I repeated the training as EXP-019 to test whether the result was reproducible. EXP-019 again achieved 90.6% mAP50 on the same clean dataset. So EXP-019 is now the best Model and the final one Model Exports The EXP-019 was exported into multiple formats for later deployment tests: Format Approximate size Intended use FP32 PyTorch 5.5 MB Development and reference inference INT8 TFLite 2.90 MB Resource-constrained edge hardware ONNX 10.1 MB Cross-platform inference and benchmarking The INT8 TFLite version is especially important for the planned Raspberry Pi Zero 2 W deployment. Its smaller size should reduce storage and memory pressure, although its real speed, temperature, and accuracy still need to be measured on the target hardware. Next Steps The next task is to benchmark EXP-019 on the Raspberry Pi Zero 2 W ordered through Stardance. The test will measure: Inference speed and end-to-end latency. Memory usage. Temperature during continuous operation.
Last Devpost Created the Website but a lot of time was lost as for some reason hackatime didnt track I am now finished couldnt bother to write a real devpost this time https://mira-vision.vercel.app/
MIRA - Revision This devlog is about fixing bugs and redoing parts of my website. It seems like my project won’t be approved because of the website and the amount of AI used for it, which I fully understand. There is just one problem: the website was never the focus of MIRA. It is purely aesthetic and was made so people can get a quicker overview of the project. Still, I complied and rewrote around 1000 lines of code, changing spacing, logic and other parts of the website. But it is still not being approved, so the next step is creating a separate, simpler website just for Stardance so the project can finally be approved. Bugs While working on the website, I wanted to test the dashboard and noticed that it didn’t seem to work anymore. I analyzed what was wrong but couldn’t really understand why. The dashboard was my first experience using FastAPI, but from the logic I understood, it should have worked. It just didn’t. So instead of trying to patch it, I decided to redo the whole backend logic of the dashboard and adjust it to work more like MIRA Live. This fixed the bug, but even afterwards I still couldn’t fully figure out what exactly caused the old version to stop working, even after asking AI and going through the code multiple times. As it had been working before Website Redesign Before deciding to create a completely separate website as mentioned above, I tried redesigning and cleaning up the current website as much as possible. I didn’t touch the color palette because I chose it myself for a specific reason, and I honestly can’t identify MIRA with another color scheme anymore. Instead, I removed things I wouldn’t have been able to code myself, like certain slide-in animations and more complicated spacing. I also rewrote parts of the logic that I didn’t properly understand before and replaced them with simpler solutions that I actually understand. Next steps Hopefully i can get approved soon and will be able to finnaly work on the next project. Iam probally goint to try one more time to redesign the website and if that doesnt work I will create a new one which i just think is unecssary, because as I said MIRA is a computer vision model and research pipeline coded mostly by hand and the website was just generated quickly for asthetic reasons and truth be told isnt necessary at all
MIRA - Revision 2 This phase was just about bug fixin, way to many bugs i dont know where they even came from. Pipeline I first started with the research pipeline for some reason it wasnt really activated like the CLI wasnt running because I initialied the pipeline in the wrong order so I fixed that. Camera Engine After the reviewer came back to me and told me that my camera engine for the dashboard wasnt working I say down and did a whole redesign to make sure it works and looks good. The main bug was just as before that I didnt cover edge cases and initailised the camera engine in the wrong order. #Website I did another redesing of the website though not much changes i just rewrote logic and cleaned up the docs page again. Next Steps So first of all for some reason this devlog is 10 hours idk how its this much prob a kind of bug which I need to analyse. I will now continue cleaning up the entire codebase for bugs and hopefully push it one last time and get accepted
Ships:
MIRA — Machine Intelligence for Recycling Automation Project Overview MIRA is a computer-vision system designed to identify recyclable materials and prepare the results for automated sorting. Its purpose is to connect camera and robot arm. For automated trash recycling The system recognizes five material classes: glass, metal, paper, plastic, and trash. it utilizes YOLO11n models for the base and is selftrained on mutiple opensource datasets from various soruces MIRA ia also more than just a model file. It includes a full research pipeline for model training with the following features, registering datasets, merging sources, remapping labels, validating YOLO annotations, creating reproducible splits, training detectors, evaluating results, benchmarking models, and exporting them for different environments. To do that it uses a command-line interface which can run live inference, starts the dashboard, manages datasets and models, launches training, evaluates detectors, compares performance, exports formats, and runs diagnostics. MIRA supports 3 kinds of models FP32 PyTorch model, an ONNX and an INT8 TFLite export. The TFlite versions is meant for rasberry pis though benchmarks are still missing Mira also posses a dedicated website. For information and docs....
|
1793072874.205264
|
1793159274.205264
|
|
18394
|
myMusic by @cluelessfr | Stardance
|
cluelessfr
|
3
|
105.0
|
1498
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-01T04:09:47Z", "hours": 49.0, "multiplier": 12.73, "payout": 608, "blessing": "neutral", "text": "I made myMusic, a Windows/Linux app that allows you to download your favorite songs. It works by searching YouTube/YouTube music for videos of your song. Then, using yt-dlp, it is able to download your song as an mp3 file. Finally it adds all of the metadata, allowing you to properly listen to your music offline. This is ship #3 of my project, so let me explain all of the changes since the last ship: First I finally added support for playlist and album downloads. Now instead of putting in each separate track individually you can combine it into a playlist and download that all together. For this I also had to update the GUI in order to fit all of the song information together. Second I improved the song searching and reliability. I made things consistent with how YouTube expects them (ASCII, Unicode characters, etc.). I also combine YouTube Music and YouTube candidates, so you get the best of both worlds. The app also tries multiple candidates before declaring that track a fail. Third I introduced explicit-version matching. Before, you would sometimes get the clean version of an explicit song. To fix this I switched to ytmusicapi, which allows me to compare matches to determine which one fits the criteria the best. The API also allows me to see whether or not the song is clean, which makes matching easier. Fourth (and probably the biggest update) I was able to add a Spicetify extension with the app. Because of this you are now able to download your favorite songs directly from the Spotify windows app. It reuses Spotify’s native download button rows, which make it easy to download your songs. It also preserves native behavior if you are already on Spotify Premium. It also shows notifications about the status of your download. This is only available on Windows. Fifth in order to make the Spotify integration work, the app now opens up a FastAPI/Uvicorn server bound to 127.0.0.1:18492. I chose a far away port in order for it not to affect any other local host processes. Sixth I also added background behavior for the app. This keeps the app open in the background without it being open on the gui (you will still be able to see it in your system tray). This allows the Spotify integration to run seamlessly without interfering with your every day work. Seventh I greatly improved the in app updater speed. Before it would greatly lag your computer because the chunk sizes were so small and it had to do a lot of writes to your disk. Now I increased the chunk size, and updated the packaging configurations to further boost the download speed and app size. These were all the main updates I did to my app, hope you like it!", "repo": "https://github.com/cluelessfr/myMusic", "demo": "https://github.com/cluelessfr/myMusic/releases/tag/v2.0.1"}, {"ship_num": 2, "ts": "2026-07-06T17:31:14Z", "hours": 34.0, "multiplier": 18.59, "payout": 611, "blessing": "neutral", "text": "I made myMusic, a Windows desktop app that takes a Spotify track link, previews the song details, finds a matching audio result, downloads it, converts it to MP3, and saves it with basic metadata tags. This is Ship #2 of my project. There have been a quite a few changes since my last ship, so let me list them all: First I added a folder-picking dialog. This allows the user to change the directory their songs are downloaded to, instead of being forced to always download to the “Downloads” directory. The app also saves the last chosen directory, so even if you close and reopen the app the directory is still saved. I then bundled Deno into the app, which helps yt-dlp solve JS challenges. Then I added the Spotify oEmbed metadata as fallback metadata if the SpotifyScraper python package fails. I also added YouTube as a partner with YouTube Music to get the best results from both platforms. I then a ranking system for the songs. The program adds and removes points from the top 6 matches from both platforms based on a few criteria, then it tries downloading from highest to least ranked. Then I also started embedding cover art. The app now takes in the cover art link, streams it, then writes it to the audio file. Next I added in-app update checking. The app can search the github repo for the latest version, checks to see if it is newer, then can automatically download and installer it. I also polished up the UI so that the controls and labels are more organized. Finally, I added Linux x64 and Linux ARM64 support. This has the same behavior as the Windows app, but the dependencies are now installed natively on that platform, which makes the app run more reliably on Linux. The current latest version at the time of this ship is v1.3.0.", "repo": "https://github.com/cluelessfr/myMusic", "demo": "https://github.com/cluelessfr/myMusic/releases/tag/v2.0.1"}, {"ship_num": 3, "ts": "2026-06-18T06:15:48Z", "hours": 22.0, "multiplier": 13.37, "payout": 279, "blessing": "neutral", "text": "I made myMusic, a Windows desktop app that takes a Spotify track link, previews the song details, finds a matching audio result, downloads it, converts it to MP3, and saves it with basic metadata tags. The hardest part was turning it from a local Python project into something other people can actually run: bundling FFmpeg, building the Windows executable, creating an installer, and writing clear install/testing instructions. These were all new steps that I wasn’t familiar with before, so I had to heavily research them and get familiar with them before shipping. I am proud that I was able to get it working as a real, bundled Windows desktop app, instead of a small project that runs only on my computer. To test it, use the Try Project link, download the v1.0.1 Windows installer, install it, open myMusic, paste a Spotify track link, click Preview Song Details, then click Download. The finished MP3 should appear in your Downloads folder. Windows may show SmartScreen because the app is unsigned; the release notes explain how to continue.", "repo": "https://github.com/cluelessfr/myMusic", "demo": "https://github.com/cluelessfr/myMusic/releases/tag/v2.0.1"}]...
|
[{"post_id": 38621, "ts": "202 [{"post_id": 38621, "ts": "2026-08-01T03:30:24Z", "hours": 2.9203, "text": "Devlog 39: I was finally able to get the Linux guards in place, and also packaged the new builds and released them to GitHub has a new version. The guards were mostly simple, as they were just a few checks that asked what operating system the user was on. And depending on that it decided whether or not to install the Spicetify extensions."}, {"post_id": 38528, "ts": "2026-07-31T23:36:25Z", "hours": 7.4581, "text": "Devlog 38: I worked on functions that helped install the Spicetify extension into the Spicetify configuration. I had to ensure Spicetify was installer, had to find its path, had to find its extensions path, then finally copy over the extension. I also added system tray behavior and multiple instance detection for the app, so that now when you close the app it doesn’t close but instead goes to the system tray. This allows the Spotify integration to work even if the app itself isn’t visible. The multiple instance detection ensures the app runs properly, and ensures that the app doesn’t try to use the same http port twice, resulting in errors. This did take a while but now all I have to do is create guards for Linux, so that the Spotify integration only works on Windows and doesn’t create unexpected errors on Linux."}, {"post_id": 37449, "ts": "2026-07-30T06:15:53Z", "hours": 4.1092, "text": "Devlog 37: I am very close to shipping now. I added the Spotify status/progress update messages, so now you can see when the tracks have finished downloading. I also fixed three (kinda major) bugs. First of all there was an error when searching for the songs on YouTube/YouTube Music. Basically what happened was that the title didn’t follow the same ASCII conventions that was used by YouTube. Because of this the app would reject good title matches even though they were the same. This produced quite a few errors, especially when trying to download songs with apostrophes. The second error I fixed was the some songs would automatically have the clean version downloaded. To fix this I switched to the ytmusicapi python package. This package also returned whether the song was explicit or not. Because of this I was able to check whether or not the song was intended to be that way, and if not I could prevent that match from being downloaded. I did have to edit a few functions to accept the new format, but in the end everything worked. Third I fixed a simple error that messed up the searching. This time it wasn’t really a bug, but instead an edge case that I missed. I was catching keywords like “feat.” and “featuring”, but I didn’t catch words like “From (and tv show, etc.)”. Because of this some matches were getting left out. I fixed this by adding another regex pattern that removes this as well."}, {"post_id": 37238, "ts": "2026-07-29T19:53:38Z", "hours": 2.6647, "text": "Devlog 36: I am almost done with the first phase of the integration. When the download button is clicked inside of Spotify, Spicetify intercepts it and now posts a request to the open web server. Then the python script gets notified of that request, decodes it, then automatically starts downloading the song/playlist/album. The only thing is that the myMusic app has to be open while doing this, but I will remove that requirement in the future (not now). The next step would be to add status reports to Spotify so that the user knows what the status of their download is."}, {"post_id": 36598, "ts": "2026-07-28T20:17:16Z", "hours": 2.8025, "text": "Devlog 35: The app now creates its own server on a very distant and far port so that your other local host stuff doesn’t get affected. I did this with uvicorn and threading, so that creating the port doesn’t make the app freeze. With this functionality the app can get the requests made inside Spotify and automatically download them. The next step is to get the app to report the statuses of the download jobs (queued, downloading, completed, failed, etc.). Then I would actually have to connect both parts, let Spotify send messages and the app receive the message."}, {"post_id": 35435, "ts": "2026-07-26T20:46:18Z", "hours": 4.8314, "text": "Devlog 34: I have been working on creating a queue for the requests. This ensures that the user can download multiple songs at once without having to wait for the previous ones to be finished. So far I have been able to create a request id for each request. The app can update the attributes of each request, such as its status, and error message. On top of this once a request is completed the app also automatically removes that request."}, {"post_id": 31912, "ts": "2026-07-20T18:12:07Z", "hours": 3.5339, "text": "Devlog 33: The app is now able to understand and automatically download any received links. Now the problem is that Spotify isn’t able to send any normal requests to via the computer. Because of this I need to find a way for Spotify to send and get data. I know that Spotify (using Spicetify) can send and get http requests. Because of that I am planning to use FastAPI and a local http server to be able to send and get data so the app can automatically download tracks. I will ensure to keep the server in a high index to ensure it doesn’t get in the way of any other local servers."}, {"post_id": 29252, "ts": "2026-07-16T01:35:08Z", "hours": 6.2167, "text": "Devlog 32: (sorry for the late post) I have been working on a really cool feature for the app. Basically what I am trying to do is integrate the myMusic pipeline into the windows Spotify app itself. When you right click a playlist or album, there will be a menu that pops up. Usually for normal Spotify users (not on premium) there will be a greyed out download button. What I am trying to do is two things: add a download button for tracks (because there isn’t one right now), and make the playlist/album button actually work. Right now what I have accomplished is adding a new button for the track and making the playlist/album button clickable. I was able to do this by using Spicetify and its framework. Because I already have it installed on my computer I am using it to test everything out but later I will bundle it with my app. What I did was build a custom Spicetify extension (I had to learn JavaScript) that creates a new button. I was able to make the original playlist/album button work because it was only “aria-disabled”, not actually disabled. This means that it was only disabled at the UI level, but Spotify still recorded clicks. By applying some UI changes I was able to make the button look enabled and still record clicks. My next step is to actually hook this up to the Python script. I think this is a really cool feature."}, {"post_id": 28364, "ts": "2026-07-14T16:05:28Z", "hours": 2.7422, "text": "Devlog 31: This devlog was mainly focused on the efficiency and speed of updating the app. Before the data would come in really small packets, meaning the cpu would have to write to the drive about 130,000 times in total (I know 😭). I adjusted this so it now comes in larger packets so the cpu doesn’t have to do more work. I also adjusted the compression and a few other Inno Setup settings (number of threads, etc.) to make the app more efficient in general. Another issue that I found is that once the app updated (specifically in Windows, idk about other platforms) the settings app would still show the older version for some time. This was an issue with the timing, so I had to adjust some of the delays to get it to work properly. Overall I think this is a pretty good update."}, {"post_id": 27877, "ts": "2026-07-13T19:39:38Z", "hours": 6.6931, "text": "Devlog 30: I FINALLY implemented playlist and album support. At first I thought it would be simple, just looping though each song in the playlist/album. Oh was I wrong. First I had to add two more methods that looped though each song, one for playlists and one for albums. There had to be two different ones because each returned metadata differently. Then I had to kind of change the format of the whole thing, because I had to store all of the songs in a list, but currently I was only returning dictionaries from all of my methods. After getting all of that sorted out I had to actually fix the GUI/downloading part. I had to update the downloading method to handle playlist/album links, then I had to properly handle all of the status message for each song (“Ready”, “Downloading”, “Failed”). Finally I had to work on fixing the bugs I had introduced and handling the edge cases. After all of that I FINALLY had playlist and album support. One thing that was sorta tough was handling the status for each track individually. Before I was just looping through the entire list and setting all of the statuses to the same thing, but I was able to create a new method and change each song status as it was being downloaded, not for every song as a whole."}, {"post_id": 25666, "ts": "2026-07-10T02:30:59Z", "hours": 5.3094, "text": "Devlog 29: This is kind of a messy devlog, so I’ll lay it out as best as I can. First, I update the UI in preparation for playlist/album support. Before it was three static text fields that could only display one song at a time. Now I replaced it with a scrollable frame, with the ability to add more sections inside the frame for more songs. This frame also has the ability to display metadata. I also introduced a status message that shows different messages and colors depending on the status. While I was doing that (and I am not done with it), I decided to stop in the middle and fix another bug. This bug (that was reported by other people as well as my testing) prevented good matches from ranked properly. This was a problem with how I compared the titles in my ranker. To fix this I added two new functions, one that normalizes the candidate title, and another that normalizes the actual Spotify song name (mainly to exclude features and get just the song name). To do this I messed around a lot with regex patterns, so I learned a lot. Now I have to go back and continue working on the new UI for playlists and albums."}, {"post_id": 23538, "ts": "2026-07-06T15:46:31Z", "hours": 3.8236, "text": "Devlog 28: Based on feedback from my first ship, I have decided to introduce Linux support. I thought it would be easy, but it turned out to be a little harder than I thought. The first thing I had to do was rewrite some of the Path code that saves the users download directory. This is because Linux and Windows have different file systems, and I had to account for both. Then came the hard part, Packaging. For ARM, I decided to do this on my Raspberry Pi, where I downloaded the project files from git, downloaded the OS specific FFMPEG and Deno, then repackaged the app as a .tar.gz. I decided to do it this way because this is sort of simply an experimental release. For x64 I decided to use GitHub Actions, which allowed me to download the dependencies and compile without having to spin up a new Virtual Machine. I also decided to keep this as a .tar.gz. Later, once I get more feedback about the Linux versions, I am planning to release a more universal app package (.flatpak). I also had to change the update checkers, because each OS version has to check its own corresponding file. In the end this was a very unique experience and I learned a lot of things about packaging apps on Linux."}, {"post_id": 21260, "ts": "2026-07-03T03:02:23Z", "hours": 5.4692, "text": "Devlog 27: This is a pretty major update. The myMusic can now automatically download and install updates, without the user having to go and download the github repository. Before, the user would manually have to go and download the installer from github, and set it up like a completely new install. Now, the app itself has a “Check for Updates” button. This button checks the github for the latest version, and if there is a newer version available it gives the user an option to download and install that. If they change their mind during the download, there is a cancel option as well. This works by first getting the github version (latest), then seeing if the current app version matches that. If it does, the app is up to date. If not, then the app can fetch the executable using the github API and automatically download the latest installer. On top of this some inno setup tools allow the app to close the app, install the new version, and reopen the app by itself. The only caveat is that this only works starting from v1.2.0. This means that if you have an older version you will have to manually download v1.2.0 in order to start getting automatic app updates."}, {"post_id": 20302, "ts": "2026-07-01T21:16:28Z", "hours": 1.2353, "text": "Devlog 26: Added a function to help with auto-downloading new updates. I haven’t hooked it up to the UI yet, but that is my next step. The function takes in the name of the installer and the link to download it. It first downloads the installer to a temp file, then once everything is good it saves it to a real executable."}, {"post_id": 19419, "ts": "2026-06-30T18:55:12Z", "hours": 1.0339, "text": "Devlog 25: This update was about implementing the update checker from the last devlog. Now there is an in-app button that allows you to check for new updates. The implementation was similar to all the other buttons and didn’t take too long because I already had the function ready. The next step is to allow the app to actually download and install the update, instead of just pointing out it is available."}, {"post_id": 19007, "ts": "2026-06-30T05:16:32Z", "hours": 1.6642, "text": "Devlog 24: I have started adding implementations that checks for the latest version of the app from github. It uses the github API endpoint for my specific project, then reads the json to get any version information. Using that we can compare the current version to the latest version on the github to see if there are any updates available. Currently I have only created the function and am yet to implement this feature into the actual app/GUI."}, {"post_id": 18082, "ts": "2026-06-29T02:24:36Z", "hours": 1.4658, "text": "Devlog 23: Today I added the feature that embeds cover art into the mp3 files. To do this I had to first use the requests library in Python to get the image itself. Instead of downloading the image I kept it in memory using the ‘io’ library. This made the metadata tagging safer and faster. Finally the app uses mutagen to embed the cover art into the mp3 file. I used a try and except loop, which ensures that even if the cover art adding fails the mp3 file still gets returned, just without the art."}, {"post_id": 17306, "ts": "2026-06-28T01:07:06Z", "hours": 1.4167, "text": "Devlog 22 This update was about further increasing the matching strength. Before the program would automatically download the highest ranked candidate, even if it was very low. Now the app downloads the highest ranked candidate only if its ranked above a certain thresh hold. If there are no qualifying matches then the app simply returns a no matches found error. This wasn’t that complicated, but I had to modify a few functions so that the score was returned properly and in a usable format."}, {"post_id": 16647, "ts": "2026-06-27T02:18:17Z", "hours": 2.3261, "text": "Devlog 21: Now added real YouTube (YT) to the match finding instead of just YouTube Music (YTM). Before the songs were found only on YTM, but I realist that normal YT has a larger list of songs, so I decided to add that to the algorithm as well. Now, the program takes 3 songs from YTM and 3 songs from YT, and uses the ranking function I created before to sort them from best to worst. Then the program starts by trying to download the best match. If it can’t, it goes through the list until if finds one it can download. If none of them download, then it sends an error message. One thing with this step was that I tried not to repeat big chunks of code, as a lot of this was similar to the original YTM downloading method."}, {"post_id": 16559, "ts": "2026-06-26T22:37:04Z", "hours": 1.9589, "text": "Devlog 20: Added the Spotify OEmbed fallback. Now even if the SpotifyScraper python package fails we have a fallback to get as much metadata as we can. This wasn’t that hard, as I already had the file from a previous time. The hard part was accounting for all the different cases, such as the title being missing or an empty string. I had to account for all of those while integrating the new file."}, {"post_id": 15864, "ts": "2026-06-25T19:50:13Z", "hours": 0.3722, "text": "Devlog 19: Implemented the ranking feature from the last devlog. Now, the best candidates are ranked in order from best to worst, and that is the order in which they are downloaded."}, {"post_id": 15836, "ts": "2026-06-25T19:07:36Z", "hours": 0.9022, "text": "Devlog 18: I implemented a way to start scoring the candidates returned by YT-DLP. This ensures that even if the first candidate returned is not the best, the program can automatically filter out the bad ones using key words and ensure the best candidate is always selected. I have only coded this function for now, and I have to wire it in to the real app soon."}, {"post_id": 15337, "ts": "2026-06-24T22:21:13Z", "hours": 3.4889, "text": "Devlog 17: Did some major code cleanups. No new features, but made the code more efficient. Also reorganized some files. The hard part was keeping the functionality the same while trying to make the code non-repetitive and more efficient. I also tried to fix any warnings that were present in the code that were caught by the IDE."}, {"post_id": 13864, "ts": "2026-06-22T18:38:18Z", "hours": 1.5628, "text": "Devlog 16: Simple update, but I added a new error message to account for a yt-dlp botting error. Now, when YouTube sends an error saying that the request was blocked due to botting being suspected, it sends a properly formatted error message instead of the raw yt-dlp text. I retested everything to ensure the previous functionality of the app remained the same."}, {"post_id": 13481, "ts": "2026-06-22T02:29:05Z", "hours": 3.7828, "text": "Devlog 15: Improved song selection algorithm, so it selects the next best track if the first selection is invalid. Before if the first track selected by YT-DLP didn’t work/was invalid, then the whole program would fail. Now it moves on to the next if the first one doesn’t work. I also update the progress messages, so it shows which match it is trying."}, {"post_id": 11619, "ts": "2026-06-18T22:25:28Z", "hours": 3.6753, "text": "Devlog 14: I have implemented two new features. First I implemented a feature that allows users to switch the directory where songs get downloaded. This took some time, but I was able to get it in the end. It works by creating a new button which opens a folder picking dialogue. The path that the user seclects inside this dialogue then gets saved to a local json file. Everytime the user changes the path it gets saved to the json, which allows the program to always open up the last directory selected by the user. I had to implement some checks to ensure that the program would work even if the json file was missing or corrupted. The second feature is more of an update. The static “Downloading” progress message is now updated with real time info on what the program is doing. The next step would be adding a dynamic progress bar."}, {"post_id": 11117, "ts": "2026-06-18T05:51:42Z", "hours": 1.4456, "text": "Devlog 13: I added an installer .exe file, added screenshots to the readme, and added a new release on GitHub. Configuring the installer was a little hard, as I was new to this process and didn’t know where to start. I used Codex to help me figure out that I could use a program called Inno. This handled the installer file, uninstall, as well as configuring it with Windows. Codex guided me through how to set that up, and eventually I got everything working. Finally I created a new version on Git and pushed everything."}, {"post_id": 10999, "ts": "2026-06-18T00:51:48Z", "hours": 1.1539, "text": "Devlog 12: I compiled the app into a .exe, updated the readme, and pushed the first version to git. I ran into some issues when compiling the app. Specifically after the initial compiling YT-DLP couldn’t see the location of FFMPEG. Because of this I had to update the “get_app_root.py” file so it accounted for the file changes when compiling."}, {"post_id": 10925, "ts": "2026-06-17T22:01:48Z", "hours": 1.1078, "text": "Devlog 11: I added a preview button to the GUI so that users could see the song details and confirm they were right before downloading the song. also prepared for packaging this file into an executable (.exe)."}, {"post_id": 10860, "ts": "2026-06-17T20:15:14Z", "hours": 1.8986, "text": "Devlog 10: Added app.py and introduced a GUI window using Custom Tkinter. Now when users run app.py they see a new desktop window open up, see a text box and a download button. Once they paste in a Spotify link they see status messages like “Downloading”. At the end they also see the downloaded path. On top of this if there are any errors during the download (like fetching metadata), this also displays as a status message. This took a little bit because I get to get familiar with Custom Tkinter, add another function that gets called by the button, and add some safeguards/quality of life updates. The main safeguard was disabling the download button while the song was downloading, which ensured the user didn’t spam processes. The quality of life update was that the download path now wraps the text to multiple lines if the path is very long."}, {"post_id": 10426, "ts": "2026-06-17T04:14:00Z", "hours": 0.4461, "text": "Devlog 09 Simple update, but it now uses Mutagen to add track name, artists, and album name to the downloaded files."}, {"post_id": 10333, "ts": "2026-06-17T00:33:23Z", "hours": 1.6983, "text": "Devlog 08 Introduced FFMPEG to the project to be able to convert downloads from .webm to .mp3 files. Also change the song title to be the title of the song. Introduced a file check to ensure file names are valid and accepted by Windows."}, {"post_id": 10283, "ts": "2026-06-16T22:29:59Z", "hours": 1.0183, "text": "Devlog 07 The program now automatically uses YT-DLP to download the best match found. This works by using YT-DLP’s build in “Download” method. I pass in the number 1 match found by YT-DLP (built in the last devlog), and it downloads it to the users default “Downloads” folder. This is a major step in the project, and I am almost ready to ship the first version."}, {"post_id": 10156, "ts": "2026-06-16T19:30:33Z", "hours": 2.4497, "text": "Devlog 06 Major Update: Now added YT-DLP to the project. Now whenever you put in a valid link you get more than just the metadata. You also get the top 5 best matches from YouTube Music. This took a while because I had to learn to properly call and use the YT-DLP package in python. I created 3 helper functions. The first created the search query using the metadata, the second returned the search results, and the last one formatted and returned the results. I created one last function as a wrapper, such that when I passed in the metadata it returned the YouTube Music search results. When calling yt_dlp.YoutubeDL(), I got a type error when passing the parameters. This was because the package expected its own datatype, while I was simply passing a dictionary. I was able to fix this by setting the type to “Any” when passing in the argument. I also changed main.py to include the YouTube search results. Now, whenever you pass in a Spotify link you get the song metadata as well as well as the top 5 best matches from YouTube Music."}, {"post_id": 9712, "ts": "2026-06-16T04:05:09Z", "hours": 0.4872, "text": "Devlog 05 This is a pretty small update, all I did was add a small test file to be able to consistently check for errors and functionality."}, {"post_id": 9667, "ts": "2026-06-16T02:27:43Z", "hours": 3.6628, "text": "Devlog 04 This was a big change in the metadata retrieving/handling. Last devlog I explained how the new restrictions on the Spotify API made it difficult to fetch the metadata, so I had to use the public oEmbed API. This didn’t give much information and was hard to work with. After researching some more I found a python package that does the metadata fetching for me, “SpotifyScraper”. this package takes in a spotify url (which the user will be providing), and can get information like song names, artists, duration, etc. This was very useful for me when coding the metadata functions. On top of this it supports playlist and album inputs as well, which is great for future updates. I spent this time rewriting the metadata retrieving functions and cleaning everything up. I removed a few redundant functions and introduced proper error messages."}, {"post_id": 9279, "ts": "2026-06-15T16:04:31Z", "hours": 2.2303, "text": "Devlog 03 After getting the link cleaner to work, I wanted to use the Spotify API to get the metadata of the song. The problem with this is that Spotify introduced heavy limitations on its API earlier this year. Because of this I had to fallback to the Spotify oEmbed, which gives only provides the song name. I am still researching for more options."}, {"post_id": 9003, "ts": "2026-06-15T00:31:15Z", "hours": 3.3114, "text": "Devlog 02 This took a while, but I was able to make the program that strips the input down to only the Spotify link. This ensures that (for the most part) that only the Spotify link gets used, and not any other whitespace/extra characters that might have appeared. It took a while because I was researching and learning how to use the ‘re’ library in Python, and it took some trial and error/debugging to get the logic to work. How this works; The user inputs into the text field First the type of track gets identified (single track, playlist, album) Then it uses the ‘re’ library to detect the pattern of Spotify URLs and URIs. This ensures that the Spotify track is actually valid. It then uses the ‘.group()’ function to capture the matching section out of the input Finally the functions are checked to ensure everything is valid, then the type of track and song url are returned."}, {"post_id": 8718, "ts": "2026-06-14T14:15:06Z", "hours": 0.7378, "text": "Devlog 01 This is the initial commit for the myMusic project. I created the file system locally, then opened the project inside IntelliJ Idea. I kept things simple and only introduced a README for now. I ran into a few problems when pushing to GitHub. Mainly, the .gitignore was being placed inside a .idea folder (I think because I was using IntelliJ). Because of this I had to go back into the IDE and move the .gitignore into the main branch and not into a subfolder."}]...
|
Title: myMusic by @cluelessfr | Stardance
Devlogs Title: myMusic by @cluelessfr | Stardance
Devlogs:
Devlog 01 This is the initial commit for the myMusic project. I created the file system locally, then opened the project inside IntelliJ Idea. I kept things simple and only introduced a README for now. I ran into a few problems when pushing to GitHub. Mainly, the .gitignore was being placed inside a .idea folder (I think because I was using IntelliJ). Because of this I had to go back into the IDE and move the .gitignore into the main branch and not into a subfolder.
Devlog 02 This took a while, but I was able to make the program that strips the input down to only the Spotify link. This ensures that (for the most part) that only the Spotify link gets used, and not any other whitespace/extra characters that might have appeared. It took a while because I was researching and learning how to use the ‘re’ library in Python, and it took some trial and error/debugging to get the logic to work. How this works; The user inputs into the text field First the type of track gets identified (single track, playlist, album) Then it uses the ‘re’ library to detect the pattern of Spotify URLs and URIs. This ensures that the Spotify track is actually valid. It then uses the ‘.group()’ function to capture the matching section out of the input Finally the functions are checked to ensure everything is valid, then the type of track and song url are returned.
Devlog 03 After getting the link cleaner to work, I wanted to use the Spotify API to get the metadata of the song. The problem with this is that Spotify introduced heavy limitations on its API earlier this year. Because of this I had to fallback to the Spotify oEmbed, which gives only provides the song name. I am still researching for more options.
Devlog 04 This was a big change in the metadata retrieving/handling. Last devlog I explained how the new restrictions on the Spotify API made it difficult to fetch the metadata, so I had to use the public oEmbed API. This didn’t give much information and was hard to work with. After researching some more I found a python package that does the metadata fetching for me, “SpotifyScraper”. this package takes in a spotify url (which the user will be providing), and can get information like song names, artists, duration, etc. This was very useful for me when coding the metadata functions. On top of this it supports playlist and album inputs as well, which is great for future updates. I spent this time rewriting the metadata retrieving functions and cleaning everything up. I removed a few redundant functions and introduced proper error messages.
Devlog 05 This is a pretty small update, all I did was add a small test file to be able to consistently check for errors and functionality.
Devlog 06 Major Update: Now added YT-DLP to the project. Now whenever you put in a valid link you get more than just the metadata. You also get the top 5 best matches from YouTube Music. This took a while because I had to learn to properly call and use the YT-DLP package in python. I created 3 helper functions. The first created the search query using the metadata, the second returned the search results, and the last one formatted and returned the results. I created one last function as a wrapper, such that when I passed in the metadata it returned the YouTube Music search results. When calling yt_dlp.YoutubeDL(), I got a type error when passing the parameters. This was because the package expected its own datatype, while I was simply passing a dictionary. I was able to fix this by setting the type to “Any” when passing in the argument. I also changed main.py to include the YouTube search results. Now, whenever you pass in a Spotify link you get the song metadata as well as well as the top 5 best matches from YouTube Music.
Devlog 07 The program now automatically uses YT-DLP to download the best match found. This works by using YT-DLP’s build in “Download” method. I pass in the number 1 match found by YT-DLP (built in the last devlog), and it downloads it to the users default “Downloads” folder. This is a major step in the project, and I am almost ready to ship the first version.
Devlog 08 Introduced FFMPEG to the project to be able to convert downloads from .webm to .mp3 files. Also change the song title to be the title of the song. Introduced a file check to ensure file names are valid and accepted by Windows.
Devlog 09 Simple update, but it now uses Mutagen to add track name, artists, and album name to the downloaded files.
Devlog 10: Added app.py and introduced a GUI window using Custom Tkinter. Now when users run app.py they see a new desktop window open up, see a text box and a download button. Once they paste in a Spotify link they see status messages like “Downloading”. At the end they also see the downloaded path. On top of this if there are any errors during the download (like fetching metadata), this also displays as a status message. This took a little bit because I get to get familiar with Custom Tkinter, add another function that gets called by the button, and add some safeguards/quality of life updates. The main safeguard was disabling the download button while the song was downloading, which ensured the user didn’t spam processes. The quality of life update was that the download path now wraps the text to multiple lines if the path is very long.
Devlog 11: I added a preview button to the GUI so that users could see the song details and confirm they were right before downloading the song. also prepared for packaging this file into an executable (.exe).
Devlog 12: I compiled the app into a .exe, updated the readme, and pushed the first version to git. I ran into some issues when compiling the app. Specifically after the initial compiling YT-DLP couldn’t see the location of FFMPEG. Because of this I had to update the “get_app_root.py” file so it accounted for the file changes when compiling.
Devlog 13: I added an installer .exe file, added screenshots to the readme, and added a new release on GitHub. Configuring the installer was a little hard, as I was new to this process and didn’t know where to start. I used Codex to help me figure out that I could use a program called Inno. This handled the installer file, uninstall, as well as configuring it with Windows. Codex guided me through how to set that up, and eventually I got everything working. Finally I created a new version on Git and pushed everything.
Devlog 14: I have implemented two new features. First I implemented a feature that allows users to switch the directory where songs get downloaded. This took some time, but I was able to get it in the end. It works by creating a new button which opens a folder picking dialogue. The path that the user seclects inside this dialogue then gets saved to a local json file. Everytime the user changes the path it gets saved to the json, which allows the program to always open up the last directory selected by the user. I had to implement some checks to ensure that the program would work even if the json file was missing or corrupted. The second feature is more of an update. The static “Downloading” progress message is now updated with real time info on what the program is doing. The next step would be adding a dynamic progress bar.
Devlog 15: Improved song selection algorithm, so it selects the next best track if the first selection is invalid. Before if the first track selected by YT-DLP didn’t work/was invalid, then the whole program would fail. Now it moves on to the next if the first one doesn’t work. I also update the progress messages, so it shows which match it is trying.
Devlog 16: Simple update, but I added a new error message to account for a yt-dlp botting error. Now, when YouTube sends an error saying that the request was blocked due to botting being suspected, it sends a properly formatted error message instead of the raw yt-dlp text. I retested everything to ensure the previous functionality of the app remained the same.
Devlog 17: Did some major code cleanups. No new features, but made the code more efficient. Also reorganized some files. The hard part was keeping the functionality the same while trying to make the code non-repetitive and more efficient. I also tried to fix any warnings that were present in the code that were caught by the IDE.
Devlog 18: I implemented a way to start scoring the candidates returned by YT-DLP. This ensures that even if the first candidate returned is not the best, the program can automatically filter out the bad ones using key words and ensure the best candidate is always selected. I have only coded this function for now, and I have to wire it in to the real app soon.
Devlog 19: Implemented the ranking feature from the last devlog. Now, the best candidates are ranked in order from best to worst, and that is the order in which they are downloaded.
Devlog 20: Added the Spotify OEmbed fallback. Now even if the SpotifyScraper python package fails we have a fallback to get as much metadata as we can. This wasn’t that hard, as I already had the file from a previous time. The hard part was accounting for all the different cases, such as the title being missing or an empty string. I had to account for all of those while integrating the new file.
Devlog 21: Now added real YouTube (YT) to the match finding instead of just YouTube Music (YTM). Before the songs were found only on YTM, but I realist that normal YT has a larger list of songs, so I decided to add that to the algorithm as well. Now, the program takes 3 songs from YTM and 3 songs from YT, and uses the ranking function I created before to sort them from best to worst. Then the program starts by trying to download the best match. If it can’t, it goes through the list until if finds one it can download. If none of them download, then it sends an error message. One thing with this step was that I tried not to repeat big chunks of code, as a lot of this was similar to the original YTM downloading method.
Devlog 22 This update was about further increasing the matching strength. Before the program would automatically download the highest ranked candidate, even if it was very low. Now the app downloads the highest ranked candidate only if its ranked above a certain thresh hold. If there are no qualifying matches then the app simply returns a no matches found error. This wasn’t that complicated, but I had to modify a few functions so that the score was returned properly and in a usable format.
Devlog 23: Today I added the feature that embeds cover art into the mp3 files. To do this I had to first use the requests library in Python to get the image itself. Instead of downloading the image I kept it in memory using the ‘io’ library. This made the metadata tagging safer and faster. Finally the app uses mutagen to embed the cover art into the mp3 file. I used a try and except loop, which ensures that even if the cover art adding fails the mp3 file still gets returned, just without the art.
Devlog 24: I have started adding implementations that checks for the latest version of the app from github. It uses the github API endpoint for my specific project, then reads the json to get any version information. Using that we can compare the current version to the latest version on the github to see if there are any updates available. Currently I have only created the function and am yet to implement this feature into the actual app/GUI.
Devlog 25: This update was about implementing the update checker from the last devlog. Now there is an in-app button that allows you to check for new updates. The implementation was similar to all the other buttons and didn’t take too long because I already had the function ready. The next step is to allow the app to actually download and install the update, instead of just pointing out it is available.
Devlog 26: Added a function to help with auto-downloading new updates. I haven’t hooked it up to the UI yet, but that is my next step. The function takes in the name of the installer and the link to download it. It first downloads the installer to a temp file, then once everything is good it saves it to a real executable.
Devlog 27: This is a pretty major update. The myMusic can now automatically download and install updates, without the user having to go and download the github repository. Before, the user would manually have to go and download the installer from github, and set it up like a completely new install. Now, the app itself has a “Check for Updates” button. This button checks the github for the latest version, and if there is a newer version available it gives the user an option to download and install that. If they change their mind during the download, there is a cancel option as well. This works by first getting the github version (latest), then seeing if the current app version matches that. If it does, the app is up to date. If not, then the app can fetch the executable using the github API and automatically download the latest installer. On top of this some inno setup tools allow the app to close the app, install the new version, and reopen the app by itself. The only caveat is that this only works starting from v1.2.0. This means that if you have an older version you will have to manually download v1.2.0 in order to start getting automatic app updates.
Devlog 28: Based on feedback from my first ship, I have decided to introduce Linux support. I thought it would be easy, but it turned out to be a little harder than I thought. The first thing I had to do was rewrite some of the Path code that saves the users download directory. This is because Linux and Windows have different file systems, and I had to account for both. Then came the hard part, Packaging. For ARM, I decided to do this on my Raspberry Pi, where I downloaded the project files from git, downloaded the OS specific FFMPEG and Deno, then repackaged the app as a .tar.gz. I decided to do it this way because this is sort of simply an experimental release. For x64 I decided to use GitHub Actions, which allowed me to download the dependencies and compile without having to spin up a new Virtual Machine. I also decided to keep this as a .tar.gz. Later, once I get more feedback about the Linux versions, I am planning to release a more universal app package (.flatpak). I also had to change the update checkers, because each OS version has to check its own corresponding file. In the end this was a very unique experience and I learned a lot of things about packaging apps on Linux.
Devlog 29: This is kind of a messy devlog, so I’ll lay it out as best as I can. First, I update the UI in preparation for playlist/album support. Before it was three static text fields that could only display one song at a time. Now I replaced it with a scrollable frame, with the ability to add more sections inside the frame for more songs. This frame also has the ability to display metadata. I also introduced a status message that shows different messages and colors depending on the status. While I was doing that (and I am not done with it), I decided to stop in the middle and fix another bug. This bug (that was reported by other people as well as my testing) prevented good matches from ranked properly. This was a problem with how I compared the titles in my ranker. To fix this I added two new functions, one that normalizes the candidate title, and another that normalizes the actual Spotify song name (mainly to exclude features and get just the song name). To do this I messed around a lot with regex patterns, so I learned a lot. Now I have to go back and continue working on the new UI for playlists and albums.
Devlog 30: I FINALLY implemented playlist and album support. At first I thought it would be simple, just looping though each song in the playlist/album. Oh was I wrong. First I had to add two more methods that looped though each song, one for playlists and one for albums. There had to be two different ones because each returned metadata differently. Then I had to kind of change the format of the whole thing, because I had to store all of the songs in a list, but currently I was only returning dictionaries from all of my methods. After getting all of that sorted out I had to actually fix the GUI/downloading part. I had to update the downloading method to handle playlist/album links, then I had to properly handle all of the status message for each song (“Ready”, “Downloading”, “Failed”). Finally I had to work on fixing the bugs I had introduced and handling the edge cases. After all of that I FINALLY had playlist and album support. One thing that was sorta tough was handling the status for each track individually. Before I was just looping through the entire list and setting all of the statuses to the same thing, but I was able to create a new method and change each song status as it was being downloaded, not for every song as a whole.
Devlog 31: This devlog was mainly focused on the efficiency and speed of updating the app. Before the data would come in really small packets, meaning the cpu would have to write to the drive about 130,000 times in total (I know 😭). I adjusted this so it now comes in larger packets so the cpu doesn’t have to do more work. I also adjusted the compression and a few other Inno Setup settings (number of threads, etc.) to make the app more efficient in general. Another issue that I found is that once the app updated (specifically in Windows, idk about other platforms) the settings app would still show the older version for some time. This was an issue with the timing, so I had to adjust some of the delays to get it to work properly. Overall I think this is a pretty good update.
Devlog 32: (sorry for the late post) I have been working on a really cool feature for the app. Basically what I am trying to do is integrate the myMusic pipeline into the windows Spotify app itself. When you right click a playlist or album, there will be a menu that pops up. Usually for normal Spotify users (not on premium) there will be a greyed out download button. What I am trying to do is two things: add a download button for tracks (because there isn’t one right now), and make the playlist/album button actually work. Right now what I have accomplished is adding a new button for the track and making the playlist/album button clickable. I was able to do this by using Spicetify and its framework. Because I already have it installed on my computer I am using it to test everything out but later I will bundle it with my app. What I did was build a custom Spicetify extension (I had to learn JavaScript) that creates a new button. I was able to make the original playlist/album button work because it was only “aria-disabled”, not actually disabled. This means that it was only disabled at the UI level, but Spotify still recorded clicks. By applying some UI changes I was able to make the button look enabled and still record clicks. My next step is to actually hook this up to the Python script. I think this is a really cool feature.
Devlog 33: The app is now able to understand and automatically download any received links. Now the problem is that Spotify isn’t able to send any normal requests to via the computer. Because of this I need to find a way for Spotify to send and get data. I know that Spotify (using Spicetify) can send and get http requests. Because of that I am planning to use FastAPI and a local http server to be able to send and get data so the app can automatically download tracks. I will ensure to keep the server in a high index to ensure it doesn’t get in the way of any other local servers.
Devlog 34: I have been working on creating a queue for the requests. This ensures that the user can download multiple songs at once without having to wait for the previous ones to be finished. So far I have been able to create a request id for each request. The app can update the attributes of each request, such as its status, and error message. On top of this once a request is completed the app also automatically removes that request.
Devlog 35: The app now creates its own server on a very distant and far port so that your other local host stuff doesn’t get affected. I did this with uvicorn and threading, so that creating the port doesn’t make the app freeze. With this functionality the app can get the requests made inside Spotify and automatically download them. The next step is to get the app to report the statuses of the download jobs (queued, downloading, completed, failed, etc.). Then I would actually have to connect both parts, let Spotify send messages and the app receive the message.
Devlog 36: I am almost done with the first phase of the integration. When the download button is clicked inside of Spotify, Spicetify intercepts it and now posts a request to the open web server. Then the python script gets notified of that request, decodes it, then automatically starts downloading the song/playlist/album. The only thing is that the myMusic app has to be open while doing this, but I will remove that requirement in the future (not now). The next step would be to add status reports to Spotify so that the user knows what the status of their download is.
Devlog 37: I am very close to shipping now. I added the Spotify status/progress update messages, so now you can see when the tracks have finished downloading. I also fixed three (kinda major) bugs. First of all there was an error when searching for the songs on YouTube/YouTube Music. Basically what happened was that the title didn’t follow the same ASCII conventions that was used by YouTube. Because of this the app would reject good title matches even though they were the same. This produced quite a few errors, especially when trying to download songs with apostrophes. The second error I fixed was the some songs would automatically have the clean version downloaded. To fix this I switched to the ytmusicapi python package. This package also returned whether the song was explicit or not. Because of this I was able to check whether or not the song was intended to be that way, and if not I could prevent that match from being downloaded. I did have to edit a few functions to accept the new format, but in the end everything worked. Third I fixed a simple error that messed up the searching. This time it wasn’t really a bug, but instead an edge case that I missed. I was catching keywords like “feat.” and “featuring”, but I didn’t catch words like “From (and tv show, etc.)”. Because of this some matches were getting left out. I fixed this by adding another regex pattern that removes this as well.
Devlog 38: I worked on functions that helped install the Spicetify extension into the Spicetify configuration. I had to ensure Spicetify was installer, had to find its path, had to find its extensions path, then finally copy over the extension. I also added system tray behavior and multiple instance detection for the app, so that now when you close the app it doesn’t close but instead goes to the system tray. This allows the Spotify integration to work even if the app itself isn’t visible. The multiple instance detection ensures the app runs properly, and ensures that the app doesn’t try to use the same http port twice, resulting in errors. This did take a while but now all I have to do is create guards for Linux, so that the Spotify integration only works on Windows and doesn’t create unexpected errors on Linux.
Devlog 39: I was finally able to get the Linux guards in place, and also packaged the new builds and released them to GitHub has a new version. The guards were mostly simple, as they were just a few checks that asked what operating system the user was on. And depending on that it decided whether or not to install the Spicetify extensions.
Ships:
I made myMusic, a Windows desktop app that takes a Spotify track link, previews the song details, finds a matching audio result, downloads it, converts it to MP3, and saves it with basic metadata tags. The hardest part was turning it from a local Python project into something other people can actually run: bundling FFmpeg, building the Windows executable, creating an installer, and writing clear install/testing instructions. These were all new steps that I wasn’t familiar with before, so I had to heavily research them and get familiar with them before shipping. I am proud that I was able to get it working as a real, bundled Windows desktop app, instead of a small project that runs only on my computer. To test it, use the Try Project link, download the v1.0.1 Windows installer, install it, open myMusic, paste a Spotify track link, click Preview Song Details, then click Download. The finished MP3 should appear in your Downloads folder. Windows may show SmartScreen because the app is unsigned; the release notes explain how to continue.
I made myMusic, a Windows desktop app that takes a Spotify track link, previews the song details, finds a matching audio result, downloads it, converts it to MP3, and saves it with basic metadata tags. This is Ship #2 of my project. There have been a quite a few changes since my last ship, so let me list them all: First I added a folder-picking dialog. This allows the user to change the directory their songs are downloaded to, instead of being forced to always download to the “Downloads” directory. The app also saves the last chosen directory, so even if you close and reopen the app the directory is still saved. I then bundled Deno into the app, which helps yt-dlp solve JS challenges. Then I added the Spotify oEmbed metadata as fallback metadata if the SpotifyScraper python package fails. I also added YouTube as a partner with YouTube Music to get the best results from both platforms. I then a ranking system for the songs. The program adds and removes points from the top 6 matches from both platforms based on a few criteria, then it tries downloading from highest to least ranked. Then I also started embedding cover art. The app now takes in the cover art link, streams it, then writes it to the audio file. Next I added in-app update checking. The app can search the github repo for the latest version, checks to see if it is newer, then can automatically download and installer it. I also polished up the UI so that the controls and labels are more organized. Finally, I added Linux x64 and Linux ARM64 support. This has the same behavior as the Windows app, but the dependencies are now installed natively on that platform, which makes the app run more reliably on Linux. The current latest version at the time of this ship is v1.3.0.
I made myMusic, a Windows/Linux app that allows you to download your favorite songs. It works by searching YouTube/YouTube music for videos of your song. Then, using yt-dlp, it is able to download your song as an mp3 file. Finally it adds all of the metadata, allowing you to properly listen to your music offline. This is ship #3 of my project, so let me explain all of the changes since the last ship: First I finally added support for playlist and album downloads. Now instead of putting in each separate track individually you can combine it into a playlist and download that all together. For this I also had to update the GUI in order to fit all of the song information together. Second I improved the song searching and reliability. I made things consistent with how YouTube expects them (ASCII, Unicode characters, etc.). I also combine YouTube Music and YouTube candidates, so you get the best of both worlds. The app also tries multiple candidates before declaring that track a fail. Third I introduced explicit-version matching. Before, you would sometimes get the clean version of an explicit song. To fix this I switched to ytmusicapi, which allows me to compare matches to determine which one fits the criteria the best. The API also allows me to see whether or not the song is clean, which makes matching easier. Fourth (and probably the biggest update) I was able to add a Spicetify extension with the app. Because of this you are now able to download your favorite songs directly from the Spotify windows app. It reuses Spotify’s native download button rows, which make it easy to download your songs. It also preserves native behavior if you are already on Spotify Premium. It also shows notifications about the status of your download. This is only available on Windows. Fifth in order to make the Spotify integration work, the app now opens up a FastAPI/Uvicorn server bound to 127.0.0.1:18492. I chose a far away port in order for it not to affect any other local host processes. Sixth I also added background behavior for the app. This keeps the app open in the background without it being open on the gui (you will still be able to see it in your system tray). This allows the Spotify integration to run seamlessly without interfering with your every day work. Seventh I greatly improved the in app updater speed. Before it would greatly lag your computer because the chunk sizes were so small and it had to do a lot of writes to your disk. Now I increased the chunk size, and updated the packaging configurations to further boost the download speed and app size. These were all the main updates I did to my app, hope you like it!...
|
1792997767.216144
|
1793084167.216144
|
|
28030
|
Star Browser by @adri_3763 | Stardance
|
adri_3763
|
1
|
104.97
|
1079
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-28T12:07:03Z", "hours": 99.0, "multiplier": 12.69, "payout": 1079, "blessing": "neutral", "text": "I built a ligthweight and a beutiful browser with AI integrated. It was pretty easy at first but then some bugs started to appear and we had to work hard to fix them with some help of AI. I’m proud that I pulled off such a big project especially with my friend @Aron_3763 I’m so glad we finished it after all difficulties and stress. Try out the AI chat integrated into this browser and AI Memory. Let us know what you think of the project or if you have any feedback to give us.", "repo": "https://github.com/Adriii3793/Star-Browser", "demo": "https://github.com/Adriii3793/Star-Browser/releases/tag/v1.1.2"}]...
|
[{"post_id": 63889, "ts": "202 [{"post_id": 63889, "ts": "2026-09-07T22:14:07Z", "hours": 5.9744, "text": "Hello, @Aron_3763 and I fixed some bugs on Linux and made some improvements after a week of trying to test on virtual machines. It was pretty hard testing because the virtual machines sometimes took so long to load and create the app and we had some difficulties trying to fix the bugs. Plus we took a while because we had some stuff going on in our lives apparently but we hope y’all will like this browser and we’re glad it’s working now. Let us know what you think of this project, we would love to hear your feedback on it. That’s all for today soon we will upload the app. Byee!"}, {"post_id": 56554, "ts": "2026-08-28T11:07:12Z", "hours": 6.2892, "text": "Hey everyone, we finally made it. We did round of testing, fixed the last remaining issues and made some improvements. The App is almost ready to submit. We put a lot of effort into this build and we really hope you all enjoy it. Let us know what you think."}, {"post_id": 55172, "ts": "2026-08-26T17:28:31Z", "hours": 9.7044, "text": "Hello guys, we are almost done catching the bugs and fixing them. @Aron_3763 and I are doing some refinements on the code and optimizing it and in a few hours we will ship it.Hope y’all have a wonderful day.Bye bye"}, {"post_id": 54454, "ts": "2026-08-25T14:02:21Z", "hours": 10.1133, "text": "Hello guys, We’ve been trying to fix some bugs and we still have some issues with it We are trying to fix it and find the reason. Meanwhile Aron is trying to help me find out some issues too with me and testing and moral support hahah 😭 We’re still trying to find the bugs and I hope soon I will be able to ship it so y’all can try it. fun fact: we added this silly cat drooling working that represent us working on this project hahaha Hope you have a great day Byee"}, {"post_id": 53660, "ts": "2026-08-24T10:05:38Z", "hours": 16.6439, "text": "Hey guys sorry I haven’t updated you for a while, I was away on vacation and did a ton of stuff so everything has been a bit of a mess. While I was away, @Aron_3763 worked on a bunch of features for the browser. We fixed a lot of bugs, added memory to the AI so it can remember things and put in ad blockers and custom wallpapers. I also added a button to copy links from the search bar, optimized the favorite websites section and media players on the homepage and ran some tests with AI to clean up the code and prevent lag. However right now we’re having some issues in the frontend. We’ve been using AI to help us understand some of the problems and fix bugs because it started acting super strange whenever we try to use the AI chat and sometimes it just won’t respond at all. We’ve been trying to solve this for so many hours now with no luck but we’re still grinding and trying to figure it out. I will show more later byeee!"}, {"post_id": 38119, "ts": "2026-07-31T10:26:32Z", "hours": 10.4014, "text": "Hello guys Lately I’ve been working on few design changes and adding new features to make the browsing experience much smoother. We added 2 new feature Tab groups: you can categorize and group your open tabs together to stay organized while browsing. Honestly implementing this was pretty tough. It kept glitching, doing unexpected things and completely messing up the UI but after a lot of debugging with the help of AI, I managed to understand the errors and learned a lot along the way. Quick access Favorites: we updated the main start page layout and moved favorites right to the top for instant access to your most important websites. @Aron_3763 is currently working on the AI assistant + AI memory to make our built-in assistant remember past context and feel much smarter. That’s all for now baii"}, {"post_id": 36042, "ts": "2026-07-27T21:19:41Z", "hours": 15.9719, "text": "Hey guys, back with another update! Lately we’ve been spending a lot of time working on the setup of the browser, the AI, and the design. We decided to split the work to get things done. Things got pretty hard and I kept getting a lot of errors that were breaking the code but after trying many times, I figured it out and fixed all the backend issues by myself. Meanwhile, @Aron_3763 is working on the frontend, fixing bugs there and making the design look great. That’s it, byeee!"}, {"post_id": 34326, "ts": "2026-07-24T22:46:05Z", "hours": 10.0811, "text": "Hello guys! In these three days, I have been debugging some files and adding some fixes to the code. I would say it was pretty tough, but I did it with a lot of effort. Also, I have been working on the backend for AI memory and improving the AI with new cool features such as tagging tab and file uploads which @Aron_3763 worked on. For the apps, we were working on Windows, but we wanted to make it cross-platform, so we used a virtual machine to install macOS. It was pretty hard, but I luckily made it possible to use and work on my project. I also made some improvements for macOS, and now we are making it perfect. For now, we made it compatible with macOS and Windows and soon we will test it on Linux to understand it better and try to make it compatible with all operating systems. We are also trying to optimize this browser and I would say it’s pretty overwhelming, but I am glad we are seeing some progress. Let us know what you think about this project. Thanks for your attention baii!"}, {"post_id": 32333, "ts": "2026-07-21T13:18:23Z", "hours": 9.0183, "text": "Hello everyone Over the past few days, @Aron_3763 and I have been trying to solve bugs and polish the UI. We focused on fixing the window dragging and styling the tabs, including making them draggable. The tabs took a lot of effort because we ran into some crashing issues but we finally solved it. We also had some issues with Git giving us errors while trying to share our files which slowed us down a bit. Yesterday I was working on importing a webview into the page to enable website navigation. The backend has been pretty hard. I’ve spent almost 5 hours on it and I’m still working on it. Meanwhile Aron is currently styling the AI window so we can integrate AI into our browser. That’s all for now. Baii guys take care"}, {"post_id": 30352, "ts": "2026-07-17T20:34:32Z", "hours": 10.7142, "text": "Hello everyone Yesterday and today my friend @Aron_3763 and I worked together at the library each day for 8h on a project. We planned to build a fast, secure and beautiful browser. We divided the tasks after deciding to collaborate on the files. I designed the front page while Aron continued working on the window controls. We saw some issues, especially with the UI and parts of the code that wouldn’t work. However, we resolved them using AI and supporting each other throughout the process. Later, we will find the issues of the window controls, refine the UI, and if possible begin to work on the backend.This project is new for us, since we’ve never done this one before. We’re already learning new languages like Svelte, collaborating, and discovering how to create applications.Thanks for reading this. Hope you’ll support us during the process and share your thoughts on how it looksBaiii"}]...
|
Title: Star Browser by @adri_3763 | Stardance
Dev Title: Star Browser by @adri_3763 | Stardance
Devlogs:
Hello everyone Yesterday and today my friend @Aron_3763 and I worked together at the library each day for 8h on a project. We planned to build a fast, secure and beautiful browser. We divided the tasks after deciding to collaborate on the files. I designed the front page while Aron continued working on the window controls. We saw some issues, especially with the UI and parts of the code that wouldn’t work. However, we resolved them using AI and supporting each other throughout the process. Later, we will find the issues of the window controls, refine the UI, and if possible begin to work on the backend.This project is new for us, since we’ve never done this one before. We’re already learning new languages like Svelte, collaborating, and discovering how to create applications.Thanks for reading this. Hope you’ll support us during the process and share your thoughts on how it looksBaiii
Hello everyone Over the past few days, @Aron_3763 and I have been trying to solve bugs and polish the UI. We focused on fixing the window dragging and styling the tabs, including making them draggable. The tabs took a lot of effort because we ran into some crashing issues but we finally solved it. We also had some issues with Git giving us errors while trying to share our files which slowed us down a bit. Yesterday I was working on importing a webview into the page to enable website navigation. The backend has been pretty hard. I’ve spent almost 5 hours on it and I’m still working on it. Meanwhile Aron is currently styling the AI window so we can integrate AI into our browser. That’s all for now. Baii guys take care
Hello guys! In these three days, I have been debugging some files and adding some fixes to the code. I would say it was pretty tough, but I did it with a lot of effort. Also, I have been working on the backend for AI memory and improving the AI with new cool features such as tagging tab and file uploads which @Aron_3763 worked on. For the apps, we were working on Windows, but we wanted to make it cross-platform, so we used a virtual machine to install macOS. It was pretty hard, but I luckily made it possible to use and work on my project. I also made some improvements for macOS, and now we are making it perfect. For now, we made it compatible with macOS and Windows and soon we will test it on Linux to understand it better and try to make it compatible with all operating systems. We are also trying to optimize this browser and I would say it’s pretty overwhelming, but I am glad we are seeing some progress. Let us know what you think about this project. Thanks for your attention baii!
Hey guys, back with another update! Lately we’ve been spending a lot of time working on the setup of the browser, the AI, and the design. We decided to split the work to get things done. Things got pretty hard and I kept getting a lot of errors that were breaking the code but after trying many times, I figured it out and fixed all the backend issues by myself. Meanwhile, @Aron_3763 is working on the frontend, fixing bugs there and making the design look great. That’s it, byeee!
Hello guys Lately I’ve been working on few design changes and adding new features to make the browsing experience much smoother. We added 2 new feature Tab groups: you can categorize and group your open tabs together to stay organized while browsing. Honestly implementing this was pretty tough. It kept glitching, doing unexpected things and completely messing up the UI but after a lot of debugging with the help of AI, I managed to understand the errors and learned a lot along the way. Quick access Favorites: we updated the main start page layout and moved favorites right to the top for instant access to your most important websites. @Aron_3763 is currently working on the AI assistant + AI memory to make our built-in assistant remember past context and feel much smarter. That’s all for now baii
Hey guys sorry I haven’t updated you for a while, I was away on vacation and did a ton of stuff so everything has been a bit of a mess. While I was away, @Aron_3763 worked on a bunch of features for the browser. We fixed a lot of bugs, added memory to the AI so it can remember things and put in ad blockers and custom wallpapers. I also added a button to copy links from the search bar, optimized the favorite websites section and media players on the homepage and ran some tests with AI to clean up the code and prevent lag. However right now we’re having some issues in the frontend. We’ve been using AI to help us understand some of the problems and fix bugs because it started acting super strange whenever we try to use the AI chat and sometimes it just won’t respond at all. We’ve been trying to solve this for so many hours now with no luck but we’re still grinding and trying to figure it out. I will show more later byeee!
Hello guys, We’ve been trying to fix some bugs and we still have some issues with it We are trying to fix it and find the reason. Meanwhile Aron is trying to help me find out some issues too with me and testing and moral support hahah 😭 We’re still trying to find the bugs and I hope soon I will be able to ship it so y’all can try it. fun fact: we added this silly cat drooling working that represent us working on this project hahaha Hope you have a great day Byee
Hello guys, we are almost done catching the bugs and fixing them. @Aron_3763 and I are doing some refinements on the code and optimizing it and in a few hours we will ship it.Hope y’all have a wonderful day.Bye bye
Hey everyone, we finally made it. We did round of testing, fixed the last remaining issues and made some improvements. The App is almost ready to submit. We put a lot of effort into this build and we really hope you all enjoy it. Let us know what you think.
Hello, @Aron_3763 and I fixed some bugs on Linux and made some improvements after a week of trying to test on virtual machines. It was pretty hard testing because the virtual machines sometimes took so long to load and create the app and we had some difficulties trying to fix the bugs. Plus we took a while because we had some stuff going on in our lives apparently but we hope y’all will like this browser and we’re glad it’s working now. Let us know what you think of this project, we would love to hear your feedback on it. That’s all for today soon we will upload the app. Byee!
Ships:
I built a ligthweight and a beutiful browser with AI integrated. It was pretty easy at first but then some bugs started to appear and we had to work hard to fix them with some help of AI. I’m proud that I pulled off such a big project especially with my friend @Aron_3763 I’m so glad we finished it after all difficulties and stress. Try out the AI chat integrated into this browser and AI Memory. Let us know what you think of the project or if you have any feedback to give us....
|
1792997587.3734443
|
1793083987.3734443
|
|
6590
|
Flower by @IvyMycelia | Stardance
|
IvyMycelia
|
2
|
104.2
|
1193
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-07T02:27:02Z", "hours": 27.0, "multiplier": 19.07, "payout": 503, "blessing": "neutral", "text": "The compiler is written in Flower itself and currently targets C, so this release was mostly geared towards making the type system have actual Flower semantics instead of a thin little blanket over whatever the backend happened to be doing. The big additions in v1.4 were: transparent type aliases real null nullable types as ?T == T | null semantic unions like int | string explicit narrowing with is explicit extraction with as That support now works across locals, parameters, return types, struct fields, and stable field-expression chains. The work had to touch parser logic, typecheck, narrowing, lowering, codegen, bootstrap, and then all the weird regressions those changes politely dragged into the room. It was.. a process for sure What I’m most proud of is that v1.4 pushed Flower toward a clearer identity that wasn’t defined by C as much anymore. This release also brought the docs back in line with the compiler, which was LONGGGGG overdue. If you want to test it, the main things to look at are the Better Types examples and the self-hosting flow. The compiler should bootstrap cleanly, the test suite should pass, and the examples now cover aliases, nullable values, semantic unions, inference, and struct/field narrowing behavior. For those who will be testing it, DO NOTE that I develop exclusively on my MacBook which is a UNIX system! I do not have the ability to properly develop and provide releases for Linux-specificalities or non-POSIX systems. I’m extremely sorry for this, but alternatively watch the provided video to see Flower in action :) If you’re not able to test it, watch this short (crappy) video instead: https://youtube.com/shorts/DyPtIru6cjY?feature=share", "repo": "https://github.com/IvyMycelia/flower", "demo": "https://github.com/IvyMycelia/flower/releases"}, {"ship_num": 2, "ts": "2026-06-18T16:00:30Z", "hours": 38.0, "multiplier": 18.19, "payout": 690, "blessing": "neutral", "text": "Flower is a self-hosted programming language for writing simple, explicit systems code without the abstraction bloat and OOP-heavy direction a lot of modern languages have. The compiler is written in Flower itself, currently targets C, and follows a straightforward pipeline: lexing, parsing, module loading, typechecking, and code generation. Over the past few months, Flower grew from a small lexer/parser/codegen experiment in C into a way bigger language project than I couldv’e imagined. This wasn’t my first attempt at a language, but it has been my favorite! I implemented compiler-enforced module semantics, stronger type-aware codegen, real boolean support, real string support, and a small standard library foundation. Strings now have equality, .length, indexing, and explicit casts to and from @char , while modules support exported prop declarations, aliases as namespaces, and private-by-default top-level declarations. The hardest part was bootstrap stability. I ran into idempotency failures, parser edge cases, compiler corruption scares, and plenty of my own bad logic. A lot of the challenge was getting new features to work not just once, but consistently enough for the compiler to rebuild itself cleanly. One bootstrap it succeeds, and then the next I’m scrambling to figure out why the new binary executable has a corrupted parser despite just working (Still haven’t fixed that yet! It.. was really confusing and I’ve got no clue why it happened lol). I’m proud that I kept pushing through that and ended up with something much more fun to use than where I started — I mean, I don’t even have to write that much C anymore!! If people want to test Flower, the important thing to know is that it is self-hosted and still experimental, but it does work. The repo includes a bootstrap path, a test suite, and example programs covering types, control flow, memory, imports, strings, and bools. The current release is focused on making the core language feel real and usable before moving on to a larger standard library and a future non-C backend, so don’t be surprised if a C file is shoved in your face!", "repo": "https://github.com/IvyMycelia/flower", "demo": "https://github.com/IvyMycelia/flower/releases"}]...
|
[{"post_id": 79537, "ts": "202 [{"post_id": 79537, "ts": "2026-10-14T14:44:10Z", "hours": 10.3042, "text": "Integers, Integers, Integers Hello!! Been a while :) Lately I have been working on v1.6. I call it the “Usefullness” update — rhymes with Grug — because it adds a ton of long awaited features and various convenience implementations Flower DESPERATELY needs. For example, currently the progress has to do with v1.6.1, or Fixed-Width Integers . When it comes to systems programming and in-general efficiency, having various integer sizes is important as it provides an additional layer of manual control over memory and sizes. I know I would have to add them eventualy, so why not put them at the start of the Usefulness update?? I’m sure they’ll come in handy later on. What Actually Changed? Well, for starters, there’s now fixed-width integers (yay)! They’re built in types, so you declare them as you would with any other atom / primitive: type Byte = u8 type Choice = Byte | u16 type OptionalByte = ?Byte struct Packet { pair: Byte[2], size: Choice, owner: OptionalByte } A whole bunch of commits and integer-specific changes regarding indices, arity, unions, nullables, etc etc etc have been made, and they all won’t fit here so instead, take a look at the current branch ! What’s In Store? Plenty more features, you can assure yourself! There’s maybe 6 or 7 — I swear — or so commits left for this specific addition, and after that a lot more features laid out in the roadmap for 1.6! As always, thanks for sticking around and watching the fiasco that is this project become more and more estranged with every hour. Love y’all!! Ivy <3"}, {"post_id": 75225, "ts": "2026-09-29T15:04:00Z", "hours": 9.9331, "text": "Integer Types, Parser Fixes, and Segfaults! Phew — this one was biiiiiggg. Flower is pretty much just a glorified C transpiler, which is NOT what I want for it! In order to move on, the data has to be handled explicitly by the FloC. So essentially, I implemented i8 , u8 , i16 , u16 , i32 , u32 , i64 , and u64 . For now, int canonically refers to an i32 value. A New Era? With these new literals, the old hoist-sized representation had to go. The decimal source text is preserved, meaning values such as 18446744073709551615 remain after parsing without causing any overflow. Types are picked up from declarations, assignments, function arguments, return values, field writes, array-element writes, * breath in * and binary expressions! Oof, that was a mouthful. That, of course, resulted in proper errors for things like: 256 assigned to u8 −1 assigned to an unsigned type values beyond u64 unconstrained literals outside the default i32 range I Hate Memory During printing, every width is handled. Integer conditions retain existing zero / nonzero behavior, and literal types print their values rather than a character. Halfway through, I ran into sudden segfaults and memory leaks. I was taken aback, because I didn’t even change anything parser related yet. Turns out, I forgot an assignment in a declaration, which apparently the parser wasn’t able to handle (whoops!). Anyways, I fixed it by propagating errors through the compilation process, so the compiler doesn’t try to typecheck or code gen if the parser reports back errors, and instead will print them out. And that’s it! Not that’s it, but that’s all I’m going to explain for now. More specifics available on the GitHub, of course. Speaking of GitHub thank you so much to S1monr3dst0ne07 on GitHub for fixing some memory leaks in the previous version of Flower — I forgot to prune allocations before returning from a function :p Love y’all!! <3 P.S.: So glad I gave up on documentation, I was genuinely dreading workong on the project and that’s why I’ve been ianctive for a long time :c"}, {"post_id": 53525, "ts": "2026-08-24T03:18:35Z", "hours": 9.7706, "text": "Hey, it’s been a while! I’ve been finding it difficult to stay motivated for this project, especially with how the new payout system works and just my in-general inability to keep commitment despite having a lot of passion. That said, I am going back to working on this diligently, and I think to start I’m going to cut down on the documentation by making perhaps one or two changes, and then going right back to the compiler work. Documentation writing has not been the most fun for me, especially with how long it takes and how it’s so difficult to not only write language reference that works, but also keeping the same whimsy Flower should have. Thank you to everyone who’s been following this journey, and I can’t wait to see y’all later!!! With Love, - Ivy <3"}, {"post_id": 26743, "ts": "2026-07-11T18:25:46Z", "hours": 9.1964, "text": "Devlog: v1.5.1 – v1.5.5 Following all of the changes Flower has undergone, I felt it was time for some much-needed documentation. On paper this was supposed to be fairly quick, simple, and not require much brain power. Unfortunately for me I got a bit too over-zealous, and included things I thought should work, but in reality hadn’t. For example, in a lot of the code snippets I’d have something like: for i in range 0..10: print(i) end Printing non-string values was not yet supported in Flower. To fix this, I took a small detour back to v1.4 and implemented support for it — mostly in a single codegen case: if ast.data._print.value_type.base == TOKEN_FLOAT or ast.data._print.value_type.base == TOKEN_DOUBLE: fprintf(out, \"printf(\\\"%%f\\\", \") gen_expr(ast.data._print.value, out, src) fprintf(out, \");\\n\") end Afterwards I added more smoke-tests in examples/io/print.flo . Every few runs, however, I’d get a segfault. This was especially odd because it wasn’t simply an error but rather a silent memory bug. Eventually I found out where it was originating — thanks, ASan! Turns out after the new type system changes, I had forgotten to initialize some values to null / 0 in for loop handlers and a few other places. I just added typeInfo.data = null / 0 where applicable and it fixed the issue! What is v1.5, and why is this devlog so long? To answer the latter first.. I lowkey just forgot to post a devlog for the first two docs I made. That’s it. For the former question, v1.5 is supposed to be explicitly a documentation pass. First thing I worked on was structure. I cleaned up the docs layout, moved things toward a more consistent lowercase docs/ tree — I had been trying for so long to do that and I just finally got it to work — and wrote down the documentation process itself so new pages aren’t just floating about. The point was to try and make the docs feel like a book instead of a folder full of unrelated notes. I wrote and checked the language pages for types, functions, and control flow by reading the compiler itself, not by trusting my (poor) memory. That meant checking parser rules, typecheck behavior, codegen boundaries, and example files before writing anything solid. Types especially needed this, given how Flower now has enough real type machinery that the docs can quickly go from being coherent to completely incorrect: nullable sugar, semantic unions, explicit casts after narrowing, alias behavior, current member limits, and the difference between what the language wants to become and what the compiler supports currently. Functions and control flow had a similar issue. I had to document prop , return rules, direct call forms, logical conditions, range-based for , and the rough edges like break and continue not yet being enforced cleanly as loop-only. That kind of thing is small until someone learns the language from the docs and hits the edge head-first (been there, done that). What Now? I’m just going to keep writing docs. Maybe do one devlog for every new doc, or a batch of docs, who knows! I certainly don’t :p"}, {"post_id": 23761, "ts": "2026-07-06T21:49:25Z", "hours": 0.6008, "text": "Devlog: Syncing Flower’s Docs Back to Reality Just a doc cleanup lol. No code change or compiler updates. Probably did more than needed for now but oh well! The mismatch was REALLY bad. The old docs preserve old assumptions, and someone reading them could walk away with a version of Flower that no longer really exists (or, in some cases, doesn’t exist yet or never ever existed)! What changed I updated the docs that had drifted the most from reality (relatable): README.md now reflects the current type-system shape ROADMAP.md treats v1.4 as accomplished the v1.4.0 milestone doc now includes more of the outcome, not just the original plan contributor docs no longer have stale semantics structure.md is more accurate to what Flower currently is, and what still needs a fuller rewrite later Yea, that’s it."}, {"post_id": 23618, "ts": "2026-07-06T18:01:45Z", "hours": 1.6556, "text": "Devlog: Finishing Nullable Field Narrowing At this point, Flower could already narrow semantic unions through field access in the is / as case, and nullable field checks were supposed to be the obvious follow-through: if maybe_box.value != null: label: string = maybe_box.value as string end Instead, I had forgotten to remove a LOT of stale code, and thus part of it was still behaving like only plain local variables could ever be narrowed. There was also a second, smaller mismatch hiding, where null in type position was not lining up with the compiler’s actual internal null representation. ?string and string | null weren’t leading to a congruent output and at times were wobblier than they should be. So the fix was mostly cleanup, but the meaningful kind: make null in type syntax lower the same way the compiler expects remove the stale var-only branches in nullable narrowing let stable field paths like maybe_box.value and holder.box.value narrow properly The funny part is that this felt bigger initially than it actually was once fixed. Nothing fundamentally new had to be invented, I just had to stop the old code from interfering with the newer code, which once I figured out how to do so it was quite quick. I spent an embarrassingly long time figuring it out…"}, {"post_id": 22284, "ts": "2026-07-04T17:48:44Z", "hours": 1.8161, "text": "Devlog: Letting Union Narrowing Follow Field Access Before v1.4.13 , union narrowing only really worked when the thing being narrowed had a variable name due to almost every similarity check relying on name_start and name_length . This was dumb, because semantic unions already knew how to test tags and extract members. Codegen was not the issue, but rather the annoying part was that the typechecker could remember this: if value is int: n: int = value as int end but not this: if box.value is int: n: int = box.value as int end So I still had to do a little temp-variable ritual: tmp: Value = box.value if tmp is int: n: int = tmp as int end Which was gross. Not necessarily catastrophic, just gross and annoying. I wanted needed convenience What changed The compiler was remembering narrowings by variable name, not by expression shape, so box.value looked obvious in source (to me, at least), but to the typechecker it was basically some random expression and not something it could reliably recognize again later. A variable name already had a stable identity, whereas field access chain did not. So the change was to let narrowable expressions represent more than just AST_VAR_REF . For now, that only means stable dot-access chains. The typechecker can record a narrowing for an expression like: box.value and then recognize the same expression later when a cast shows up. So this works directly now: if box.value is int: n: int = box.value as int end Same for the other union members, like string . The detour My first example accidentally wandered into a different feature: if maybe_box.value != null: That exposed a real nullable-field-guard gap, but that is not what this was supposed to be about. Very rude of the test case to have ambition hmph >:( Where this leaves it Semantic union narrowing now persists past field access — at least for stable dot-access chains — and the temp-local is no longer needed. Butttt now I gotta work on nullable-field-guards, ugh (hehe)"}, {"post_id": 21926, "ts": "2026-07-04T03:34:19Z", "hours": 0.4592, "text": "Devlog: Direct Semantic Union Parameters Now instead of having to do this workaround: type Value = int | string func accept(value: Value): bool You can just pass semantic unions directly: func accept(value: int | string): bool That was it. All I had to do was remove a stale type_error clause in register_params and allow binding variables. Then I updated the two relevant accept functions in /examples."}, {"post_id": 21751, "ts": "2026-07-03T20:51:30Z", "hours": 4.9086, "text": "Devlog: Making ?T Actually Mean T | null Before v1.4.10 , ?T was treated as its own nullable system and not really integrated with the rest of the semantic unions. This was unideal, because it created a separation of logic which was cumbersome to maintain. The idea was to make the following be the default: ?int == int | null ?string == string | null ?@int == @int | null Prior to the refactor, nullable types were still mostly pointer-oriented. That worked when ?T basically meant “maybe this pointer is null,” but it did not really fit anymore once semantic unions became actual runtime values. If Flower has T | null , then ?T should use that instead of being its own special thing. This is a more pragmatic choice, as it keeps the compiler easier to manage and update later on. What changed Typecheck now lowers ?T into the same semantic-union machinery used by normal unions. That means nullable values now go through the same general path as union values: null checks use union-aware narrowing narrowed nullable values can be extracted with as codegen emits tagged union storage assignments pack into the right union member So this now works as an actual nullable flow: maybe: ?@int = raw if maybe == null: return false end real: @int = maybe as @int The annoying part is that Flower has to track two things at once: the type the programmer is allowed to see after narrowing, and the actual union shape that remains underneath it. After the guard, maybe behaves like an @int . But codegen still has to remember it came from @int | null , because apparently the compiler cannot simply “vibe” its way through storage layout. Tragic! The bugs that annoyed the heck out of me Most of the work was not surface syntax. The syntax was just standing nearby looking innocent. The actual bugs were in the places where Flower knew “this is non-null now,” but then forgot how to lower, such as: narrowed nullable values falling back to raw C casts like (int*)(maybe) false branches of == null / != null narrowing to the wrong side (this was my fault lol) null getting packed into the wrong union member That last one was the rude one. For ?@int , generated C could end up doing something like: . tag = 1 , . m0 = NULL instead of packing into the actual null member. So the value looked almost right, but the tag/member pairing was wrong. Then later null checks would fail, because the compiler had technically put null somewhere. Just not the correct somewhere. Very helpful. The fix was separating two questions I had accidentally merged: is this type compatible with this union? which exact union member should this value occupy? Those look related, but they are not the same question. Flower was using the first answer for the second problem, and then acting surprised when everything became soup. Where this leaves Better Types ?T now lowers through the same path as T | null , which means null checks, narrowing, extraction, and storage all line up with the semantic union model. This should make later work cleaner, such as nullable inference, nicer union ergonomics, maybe pattern-like narrowing eventually. Not easy. I am not saying easy near a compiler. That is how they hear you. You do not want them to hear you .."}, {"post_id": 19626, "ts": "2026-07-01T00:18:08Z", "hours": 0.4472, "text": "Devlog: Teaching Flower to Understand Guard Clauses gave Flower branch-local inference. Last update, I added support for branch-local inference, so the compiler could understand things like: if maybe == null: return false else: real: @int = maybe end and: if value is int: return false else: s: string = value as string end That was an improvement, but it still meant narrowing stopped at the end of the branch. That meant stuff like returninging in some conditions still did not really work as naturally as it should: if maybe == null: return false end real: @int = maybe or: if value is string: return false end n: int = value as int In v1.4.9 I fixed that. What changed Now narrowing propagates past very obvious guard clauses. If one branch definitely returns and the other falls through, the compiler now carries the interpretation forward after the if . This means that the compiler can now understand: after if x == null: return ... , x is non-null after if x is string: return ... , a two-member semantic union can narrow to its remaining member I kept this intentionally conservative for now. The compiler is not doing full control-flow analysis yet. It is only recognizing the simplest and most explicit early-exit shape. How it works The main addition was a small semantic check for “does this branch definitely return?” Right now that means: direct return if where both branches definitely return Once the compiler knows one side exits and the other survives, it applies the branch’s narrowing to the following statements. Yea.. that’s it lol."}, {"post_id": 19014, "ts": "2026-06-30T05:39:45Z", "hours": 1.2028, "text": "Devlog: Adding Obvious Branch-Local Inference to Flower Before this, narrowing mostly worked in the obvious “true branch” cases: if maybe != null: real: @int = maybe end and: if value is string: s: string = value as string end But the else branch was still kind of standing there empty-headed, even when the meaning was extremely obvious. Like, if this happens: if maybe == null: return false else: real: @int = maybe end then inside the else , maybe is clearly not null. So now it doesn’t!! What changed Flower now does branch-local narrowing in else for small, explicit cases. That means these now work: if maybe == null: return false else: real: @int = maybe end and: if value is int: return false else: s: string = value as string end It is only applying inference when the condition says something directly and the opposite branch has one obvious meaning. Nullable narrowing For nullable pointer-like values, Flower now understands both sides of simple null checks: if x != null narrows x to non-null in the if body if x == null narrows x to non-null in the else body the opposite side can narrow to null when that is the only meaning left Semantic union narrowing The same idea applies to semantic unions, but a bit more ‘held back.’ Essentially, if Flower sees: if value is int: then the if branch narrows to int , like before. Now, if the union only has one other possible member, the else branch can narrow too. So for: int | string the else after if value is int can be treated as string . This is not full control-flow wizardry, since it doesn’t reason across deep boolean chains, early-returns, or giant branches yet. It is deliberately small and local, because I do not want Flower “helping” so much that I need a detective board to figure out what type something is."}, {"post_id": 18478, "ts": "2026-06-29T17:18:49Z", "hours": 0.8039, "text": "Devlog: Letting Semantic Unions Work In Functions After getting semantic unions working in local declarations, the next problem was fairly obvious (and in my roadmap hehe). This did not work before: func make_value(): int | string return 7 end func accept_value(value: int | string): bool return value is int end Which was annoying, because int | string was already a real union type at this point. Flower could use it in locals, it could pack assigned values, it could check variants. But if I returned 7 from a function declared as int | string , or passed 7 into a parameter expecting int | string , the compiler did not know how to carry that union-lowering information across the boundary. This has been one of the easier changes I’ve made in a long while. It compiled properly first try (if you ignore a tiny misspell I made which I fixed really quickly), and there were no prior hidden bugs that surfaced. This.. is too suspicious. What changed The compiler now carries semantic union info through: function parameters function returns imported alias calls If a function expects: int | string and I call: accept_value(7) typecheck records that 7 needs to be packed as the int member of that union. Same for returns: func make_value(): int | string return 7 end That matters because codegen cannot guess later due to the separation of responsibilities I’ve laid out. By the time Flower is emitting C, it needs to know which tag to set and which member to write. Lowering it properly Codegen already knew how to pack union values for declarations and assignments. The missing part was doing the same thing for call arguments and return statements. So now a value can be packed into a tagged union when it is: stored locally passed into a function returned from a function Alias calls got handled too, so things like: remote.accept(11) remote.make_string() do not become their own weird little cursed island. Why this mattered Without this, semantic unions only worked as long as I never organized my code. They worked in local tests, but not in helper functions, imported providers, or normal inputs and outputs. Now union values can actually move around the program instead of being trapped in the one scope where they were declared — and for me, forgotten! Very exciting, the union can leave the house. They grow up so fast ⁎⁍̴̛ ₃ ⁍̴̛⁎"}, {"post_id": 18151, "ts": "2026-06-29T05:17:03Z", "hours": 3.3186, "text": "Devlog: Semantic Unions Become Actual Values (Part I) In v1.4.6 , I made semantic unions actual runtime values instead of just parsed/typechecked shapes. Before this, Flower could understand: type Value = int | string as a type. It could point at it and say, “yes, that is a union,” but that was mostly theoretical. The goal was to make this work-work for realsies: type Value = int | string value: Value = 7 if value is int: n: int = value as int end value = \"Ivy\" if value is string: s: string = value as string end That meant Flower needed more than TypeInfo.is_union = true . It needed a full path from syntax, to type proof, to lowered storage, to runtime extraction. Otherwise unions would just be fancy typechecker thingy-ma-bobbies, which is not very useful when the backend still emits C. What changed Instead of treating a union as a vague “one of these types, probably,” Flower now lowers it into a tagged structure. Conceptually, this: type Value = int | string becomes something like: struct Value { int tag ; union { int as_int ; flower_string as_string ; } data ; }; Not the final sacred form forever, but that is the shape of it: a tag saying which variant is active, plus storage for the possible members. Since Flower emits C right now, the lowering is C-shaped. I am not fully sure how I want this to look in ASM yet, but I do know it would be way more technical, and uglier. This required a few things to play nicely with one another: if value is int creates a union proof the guarded branch stores narrowing information value as int is only allowed after proof assignments pack values into the right tagged member explicit casts extract the right member from storage Otherwise the compiler is just writing checks its own backend cannot cash. The part that makes it ACTUALLY semantic For pointer narrowing, if value is T mostly refines how the compiler treats an existing value. For semantic unions, the check also becomes a runtime tag test. So this: if value is int: means: check the active tag of value , then inside this branch, treat it as the int variant. Then this becomes valid: n: int = value as int because the branch already proved the active variant. Without that proof, value as int should not be casually allowed. Flower is supposed to be explicit, not psychic, and I am not confident enough yet to implement a proper intuitive implicit checker without summoning something cursed. Assignment and extraction This: value: Value = 7 now packs 7 into the int member and sets the tag to the int variant. Then this: value = \"Ivy\" does the same thing, but for the string member. So a semantic union is not just some bytes, but rather a tagged runtime object where Flower knows which member is active. Then explicit casts like: value as string can lower into extracting the string member, but only when the typechecker has accepted that the operation is safe in that control-flow path. Why this checkpoint matters Flower can now store variant values, prove which variant is active, and require explicit extraction instead of relying on random magic I threw together. The flower has grown another concerning little organ."}, {"post_id": 16395, "ts": "2026-06-26T17:55:41Z", "hours": 2.0825, "text": "Devlog: is Checks v1.4.5 added is checks, mostly so code like this can work: if maybe_ptr is @int: real_ptr: @int = maybe_ptr end The idea is (fairly) simple: if the condition proves maybe_ptr is an @int , the inside of the branch should be allowed to treat it like one. Flower did not know how to do that before. It knew what a variable was declared as, but it did not really learn anything from control flow yet. Now it can, at least for the pointer/nullable-ish cases I care about first. This touched the parser, AST, typechecker, narrowing logic, and codegen. So, naturally, the “small feature” went everywhere. I’d actually consider this one of the bigger refactors so far, mostly because it added a new TypeAtom structure. Before this, types were still a bit too attached to the places they appeared, and all fell under the TypeInfo . That worked for simpler declarations, but is checks needed type syntax to have something the compiler could pass around to use for comparisons, validations, and narrowing. The parser had to recognize the new expression shape. The AST had to store the left side and the tested type. The typechecker had to make sure the test was allowed and not totally garbage. Then the narrowing logic had to say, “inside this branch, this variable has the proven type of x and therefore we won’t flag you for being an idiot.” That last part was where the bug goblin lived. I’m calling them a goblin because they were sneaky (and I also think it’s quite a funny and cute name). For a while, Flower had applied narrowing from the if body instead of the if condition, which meant the compiler saw this: if maybe_ptr is @int: real_ptr: @int = maybe_ptr end and somehow still failed on the assignment inside the branch. Very helpful. Thank you, compiler. EVen though it’s obviously 100% my fault, I made the compiler, but oh well!! Once I changed the narrowing step to inspect the actual condition expression, it started behaving like it should. The typechecker could see maybe_ptr is @int , attach that narrowed type to the branch scope, and allow maybe_ptr to be used as @int inside the guarded block. For now this explicitness is how I want it. There may come a time in the near future where I decide some implicity is ok, but we’ll see ;) is checks are the first real step towards control-flow-aware typing in Flower. Not full union support yet, but definitely the beginning of that road soon to come. Right now it mostly helps with nullable and pointer-like cases. Later, the same idea can support richer unions, better narrowing, and more type-driven control flow without making the programmer manually restate everything the compiler should already know. Also, it bootstrapped cleanly twice — which.. is obviously the bare minimum, but still!!"}, {"post_id": 15458, "ts": "2026-06-25T04:05:50Z", "hours": 2.4619, "text": "v1.4.4 Devlog: Giving Flower Real Semantic Union Types I made it so that semantic unions are now in Flower’s parser and type system — but not yet its codegen. The goal was to support types like: value: int | string next: @Node | null type Result = int | string What’s new The parser now understands | inside type positions and builds semantic union type information instead of relying on those old plain aliases or backend-shaped hacks. On the typecheck side, unions are now carried through normal type copying and alias resolution. That means named aliases like: type MaybeName = string | null make sense after resolution, instead of collapsing into nonsense. The typechecker also now accepts union-compatible usage in the places that matter for a foundation: variable initialization assignment parameter passing return checking alias resolution So if a value matches one union member, it is accepted. This is sorta implicit behavior, but I think it gets a pass due to its somewhat explicit nature? What it does not do yet This version was intentionally strict about using unions as values. You cannot yet directly: index a semantic union access a field on a semantic union use arithmetic / comparison operators on one print one directly Instead, Flower now requires an explicit cast before using a union value that way. That may sound harsh, but it is the right restriction.. for now. There is not any narrowing yet, so pretending unions were fully usable would just make the language lie and spit out 2,000 errors. Where this leaves v1.4 Flower now has: transparent type aliases null as a real type-system concept pointer-first nullable types semantic union type representation The next step is the part that will make unions actually usable rather than merely legal: narrowing with is better explicit extraction with as eventually making ?T truly become T | null instead of remaining pointer-first for now No fun screenshot this time :p just frontend work for now… Ivy, signing off <3"}, {"post_id": 14511, "ts": "2026-06-23T17:31:39Z", "hours": 1.8206, "text": "Devlog: Adding Pointer-First Nullable Types to Flower I worked on giving Flower its first real nullable type surface without being overambitious and pretending the compiler is ready for full optional-everything semantics yet. The new syntax now works like this: ptr: ?@int = null text: ?@char = null That means there is now an explicit way to say “this pointer-like value may be absent,” instead of relying entirely on raw pointer habits from C (If you couldn’t tell by now, I despise C). What changed The main work was split across lexer, parser, and typecheck. I added: ? as a type marker in type positions is_nullable tracking in TypeInfo type rules for nullable pointer/reference values explicit compatibility for: assigning null into nullable pointer-like types comparing nullable values against null casting between @T and ?@T I also kept the scope intentionally narrow: this implementation is pointer-first nullable support , not full nullable scalars. So ?@int makes sense right now, but ?int is still deferred until I make a better semantic union / optional representation for plain values. Why this matters It would have been easy to overreach here and claim “nullable types are done,” but that would have been a big phat lie. Pointer-like nullability lowers naturally enough with the current backend and current compiler model. Scalar nullability, however, does not. Once you let int or bool become nullable, you need a more real representation for “has value / no value,” and that belongs in the later union work, not here. Result explicit absence compiler-owned semantics better future unions stronger type meaning without hidden magic The next real step after this is not more patching around null — I consider that done for now — but instead giving Flower the deeper machinery needed for nullable non-pointer values and semantic unions later in v1.4 so it doesn’t come back to bite me in my butt."}, {"post_id": 13935, "ts": "2026-06-22T21:20:58Z", "hours": 0.355, "text": "Devlog: Formalizing Flower’s Null Foundation Flower already had some of the pieces for null , but they were a bit scattered. The goal here was to make it explicit, consistent, and safe before moving on to nullable syntax like ?T or full union-based nullability later in v1.4 . Another shorter devlog, but still important and distinct enough for me to think “Hmm devlog time? Yes, devlog time!” What changed The main work was in typechecking. I added to the compiler’s idea of what null is, how it is represented internally, and what kinds of values are actually allowed to accept it. Rather than letting null-related behavior stay implicit across a few checks, null now follows a clearer rule set: null has one centralized internal type representation pointer-like values can explicitly accept null null comparisons and assignments now go through the same semantic path Why this matters This isn’t all that important on its own, but it matters a lot for where Flower is going next. If null is not defined well, then later features like: ?T better unions smarter narrowing more expressive type flow all become more error-prone (or so I assume given my track record) than I want need them to be. Validation I also expanded the example coverage so null : it now has dedicated behavior checks around assignment, passing values around, and comparison behavior."}, {"post_id": 13918, "ts": "2026-06-22T20:30:15Z", "hours": 1.0089, "text": "Devlog: Fixing Flower’s Compiler Process So It Stops Fighting the Host This wasn’t really about language design at all buttttt it is much more embarrassing , AND more important: Flower’s compiler process itself was too fragile. The immediate issue showed up on Linux, specifically NixOS (thanks shipwrights <3). The build flow was assuming too much: a previously existing bin/Flower could be reused safely bash would exist at the expected path clang would always be available the checked-in compiler binary would be runnable on whatever machine the repo landed on That worked well enough on my machine until it didn’t. On NixOS — and by extension probably any other machine without the prexisting binaries I had — it broke: make targets were inconsistent, the shell script failed on interpreter assumptions, and the compiler binary itself could be the wrong format for the host. What changed The fix was to separate “the compiler source exists” from “the current compiler binary is usable on this machine.” The build process now starts by compiling a fresh host-native bootstrap compiler from bin/Flower.c , instead of trusting whatever happens to already exist in bin/Flower . That means the flow is now: bin/Flower.c -> host-native bootstrap compiler -> new Flower compiler -> self-check instead of: maybe existing bin/Flower -> hopefully works -> maybe bootstrap Ok well that’s kinda a lie; it still relies on hopes and dreams to bootstrap sometimes. BUT it’s MUCH safer! And now everyone gets to experience crippling bootstrap anxiety, instead of being met with a failure before the actual compiler gets to.. well, do its thign! I also cleaned up the surrounding tooling: switched the bootstrap script to portable sh restored a clearer build / bootstrap / rebuild / test / clean structure made the compiler use CC and CFLAGS from the environment instead of hardcoding clang What this actually improves Flower is still not universally cross-platform yet. The compiler driver still has POSIX-shaped assumptions in places, and the emitted C can still depend on host APIs depending on what the program uses. I’m not yet at the point of wanting to make it completely universal, especially given how I’m only one person and with v2.0 coming up soon it’d — in my humblest of opinions — be a waste of time. I am honestly grateful for people reviewing my code and otherwise viewing it catching onto details I have overlooked. My goal is to not make a ‘just-barely working on my machine’ project; I enjoy sharing development with others, and it hurts knowing people can’t appreciate code, whether it be mine or others’, due to something as simple as hard-coded sh flags."}, {"post_id": 13822, "ts": "2026-06-22T17:23:16Z", "hours": 3.7814, "text": "Devlog: Making Flower’s Type Aliases Transparent This version was simple to develop on paper (and even in practice it wasn’t too bad, only around 4 or so hours!): type Count = int type Total = Count type Name = string and then have those aliases behave like the real type everywhere: n: Count = 12 total: Total = identity(n) name: Name = \"Ivy\" if name != \"Ivy\": return false end if name.length != 3: return false end That meant aliases could not just be parsed and stored, but rather had to be transparent to the compiler’s semantic checks. What changed I added type alias declarations to the AST, parser, and type environment, then added the ability to resolve aliases in typechecking before comparing types. That included: return type checks variable initializers function call arguments binary comparisons string-specific comparison logic struct field access The important rule here is that aliases are semantic, not codegen-facing. Count should behave as int , Name should behave as string , and chained aliases like Total -> Count -> int should collapse correctly. In the future, especially post v2.0 , this could change and custom types might become real — but for now, they’re just aliases. The bug that exploded bootstrap The first real failure was not in aliases themselves, but in function argument checking. Inside check_call_args(...) , the compiler was resolving the argument expression into expected_type instead of arg_type . That overwrote the parameter type, left the actual argument type uninitialized, and caused the second bootstrap stage to explode into over a thousand misleading errors. This was not a pre-existing issue, it was instead from human error (my error) during the initial implementation where I accidentally put the wrong variable. Once that was fixed, the remaining failures were much more helpful than the bright flash of red and “Typecheck failed with 1224 error(s)” message! Where this leaves v1.4 With the first step toward “better types” done, aliases are no longer just syntax. That gives v1.4 a solid base for whatever comes next in the type system without having to fake around raw names. During this whole dev session, I did discover that a whole lot more of the source code was left using legacy work-arounds: int instead of bool , name_start; name_length and @char instead of string . In all fairness, some of these aren’t exactly the easiest to refactor. However, I will probably hold off on refactoring the codebase until either right before v2.0 , or right after. Just know it’s on my radar ;)"}, {"post_id": 11351, "ts": "2026-06-18T15:46:42Z", "hours": 1.4231, "text": "Devlog: Cleaning Up v1.3 For Release After many hours of work, bool and `string finally became real, and it was time to cleanup the mess I left behind from the version’s development. Mainly the only thing worked on was some cleanup: roadmap now reflects actual v1.3 features and implementations updated README and contribution documents to match the current compiler pipeline cleaned up string examples so they have the full intended v1.3 style instead of some leftover testing usage pushed the compiler’s version to 1.3.0 updated help / usage text so it matches the new output-path and auto-run behavior Prior to this, if I had just merged and shipped, the release wouldv’e been messy: README, Contributing, example files, and guidance commands were all mixing older details which made it confusing — even for me — when trying to explore the language and what it has to offer. For a bootstrapped compiler especially, making sure everything is cleaned up and polished is something that should not be ignored. I’m definitely guilty of overlooking this, but I’ve outlayed a whole plan for v1.3 unlike past versions, and part of it was setting up a proper versioning system and polishing its release as it goes. This format will be adopted in future versions, since it’s just way cleaner and nicer to look at. Future work At this point, v1.3 is done and has implemented, at minimum, a concrete foundation for post-v2 bools and strings. Next will likely be more subtle improvements, and features that are currently reliant explicitly on C rather than Flower-hosted code. In order for v2.0 , Flower will have to be effectively independent from C if it wants to emit machine code. Currently I am planning on adding features such as Type Aliases and maybe a stdlib prior to that, but anything can change!! Thanks for being here for all of v1.3 <3"}, {"post_id": 11116, "ts": "2026-06-18T05:51:28Z", "hours": 1.7269, "text": "Devlog: Giving Flower an Internal cstr Foundation Even after Flower got a real string type, the compiler itself was still leaning directly on C-style string helpers for its own internal work. That meant a lot of Flower source was still semantically depending on libc behavior: !strncmp(...) strcmp(...) strlen(...) strcpy(...) strncpy(...) strdup(...) strrchr(...) That is not where I want the language to stay. What changed I added a new internal module: import \"src/stdlib/cstr.flo\" as cstr and gave it compiler-facing helpers like: prop func len(s: @char): int prop func eq(a: @char, b: @char): bool prop func eq_n(a: @char, b: @char, n: int): bool prop func copy(dst: @char, src: @char): @char prop func copy_n(dst: @char, src: @char, n: int): @char prop func dup(src: @char): @char prop func find_last(src: @char, ch: char): @char This helper module is essentially the precursor to a future strings.flo library that can be distributed. But for now, it uses a basic API layer purely meant for in-house usage. Then I migrated compiler internals over to that module across: src/parser.flo src/module.flo src/lexer.flo src/typecheck.flo src/codegen.flo src/globals.flo src/main.flo So instead of using C-string behavior directly everywhere, the compiler now goes through Flower-owned helpers first. The Compiler Strikes Back This was one of those changes that sounds mechanical until it absolutely is not. A big trap was that old code often relied on C comparison functions returning 0 on equality, so patterns looked like this: not strncmp(...) But cstr.eq_n(...) returns an actual bool , which means blindly rewriting those calls gives inverted logic. So this: if ps.alias_lengths[i] == tok.length and not cstr.eq_n(...): was completely wrong. It had to become: if ps.alias_lengths[i] == tok.length and cstr.eq_n(...): That bug showed up in alias parsing first, which made it especially cursed, because it caused normal namespace-style calls like cstr.eq(...) to stop parsing correctly and crash the bootstrap path in confusing ways. I spent way longer than I wish to admit on trying to figure out why it wasn’t playing nice. But, once I figured it out, it was a really quick fix (I literally just cmd + f ’d not cstr and replaced it with cstr lol). Are we done yet..? This does not mean Flower is free from the C backend yet. It does mean something important, though: compiler logic is starting to depend on Flower-defined helper semantics instead of scattered raw libc calls. That is a much better stage for the future backend story, because when C eventually stops being the primary lowering target, the compiler will already have more of its own vocabulary. In other words, this was less about “remove C” and more about “stop letting C define the language’s internal habits.” Nah just kidding, I really wanted that bloated “builtin_c_call” stuff gone. Unfortunately I only managed to skim it, but that’s closer than before! Result After fixing the migration mistakes and the alias/parser fallout, the compiler bootstrapped successfully again. Flower now has an internal cstr layer, and compiler string handling is a little more its own."}, {"post_id": 11068, "ts": "2026-06-18T03:16:30Z", "hours": 1.2611, "text": "Devlog: Fixing Flower’s Output Driver and Starting the String Stdlib This checkpoint was really two different kinds of progress that ended up helping each other a lot. The first part was not glamorous, but it was necessary: Flower’s compile driver was tripping over its own default output naming. This was a known issue that I had been putting off, but for some reason it really annoyed me this time so I decided enough and to fix it. If no explicit output path was provided, the compiler would generate output.c , then strip the .c and try to emit a binary named output . That worked fine right up until the repo itself already had an output/ directory. At that point, linking failed because the compiler was trying to create a file where a directory already existed. Worse — because it annoyed me more — the driver logic was also mixing up “the generated program exited non-zero” with “compilation failed.” That became especially annoying during bootstrap, because the generated compiler binary would run without CLI arguments, print its own usage error, and then cause bootstrap to report failure even though codegen and C compilation had both succeeded. So I finally got off my butt and cleaned that up. Driver Cleanup The default output path now goes to: output/out.c which naturally produces: output/out as the binary. That avoids the old output filename collision. I also separated compile success from auto-run behavior: explicit output path: compile only default output path: compile, then auto-run if appropriate That means bootstrap no longer “fails” just because the compiled compiler exits non-zero with missing arguments, and demo/test files can still run automatically when that is actually useful. This sounds like a small driver fix, but honestly it removed a lot of noise from string work — and more — immediately. String Stdlib Beginnings Once that output weirdness was under control, I could finish doing what I just started and actually wanted: making string behavior live in Flower instead of endlessly leaning on ad hoc C calls (Call back to last devlog, absolute ball knowledge!!). So I added the first real reusable helpers in src/stdlib/string.flo : is_empty(s) starts_with(s, prefix) ends_with(s, suffix) find_char(s, ch) These are intentionally simple. They mostly exist to prove that the current string support is now strong enough for normal library code to be written on top of it. Not incredibly useful, at least at the level the compiler needs, but at least I could translate some AP Comp Sci A into Flower hehe A string feature does not really feel “real” until I can build helpers with the language itself instead of only teaching the compiler more special cases. The day I remove the builtin C handlers is the day I’m at peace… Validation To exercise that new library surface, I changed string_pass.flo to now act as a small pass file for the experimental library. Its job is not to be impressive. Its job is to answer a more important question: can I import string helpers, call them from normal Flower code, and get expected results through the full compile pipeline? At this point, yes. Where this leaves things This checkpoint did not remove all C string dependencies from the compiler. In fact, it removed essentially none! That is still a separate step, one that may even be in v1.3.7 ;) But it did establish two important things: Flower’s output/driver behavior is now much less annoying. We can start growing a real string library in Flower itself. That is a good place to be, because the next string work can build outward from a stable driver and an actual library surface instead of piling more special behavior into the compiler."}, {"post_id": 11013, "ts": "2026-06-18T01:18:51Z", "hours": 1.0825, "text": "Devlog: Adding String Indexing to Flower This one was fairly quick, and was about making one very normal-looking thing actually work: name: string = \"Ivy\" as string first: char = name[0] That sounds small, but once string became a real Flower type, indexing could no longer piggyback on the old “arrays and pointers only” behavior. The compiler needed to understand that string[index] is its own case. What changed I taught the typechecker to treat string subscripts as char . That means: string[index] now resolves to char the index expression must be an integer string indexing is readonly for now So this is valid: first: char = name[0] but this is not: name[0] = 'X' I wanted reads first, writes later. That keeps the rules simple while the string representation is still compiler-owned. I’m not sure how writes would work with a C backend, due to how ‘strings’ are allocated. Perhaps a feature for post-v2.0? Lowering it to C Since Flower strings currently lower to a struct with .data and .length , codegen needed a special path for string subscripts. Normal arrays and pointers still lower like: arr [ index ] but strings now lower like: name . data [ index ] That keeps the generated C valid without changing how regular subscripts work elsewhere in the language. So something conceptually like: This checkpoint also forced one strict-but-correct rule that required me to update a WHOLE SINGLE LINE (hehe): arg[i] = tolower(arg[i] as char) to arg[i] = tolower(arg[i] as char) as char Because tolower(...) is effectively treated as returning int , assigning it back into a char subscript needs an explicit cast. I kept that strictness on purpose. I do not want Flower silently narrowing values just because C would let it. Validation I expanded the string example coverage to check: string indexing returns the expected chars string[index] works alongside string <-> @char casts bootstrap still succeeds repeated bootstrap succeeds tests still pass Which, after all the recent bootstrap chaos, was very nice to see. Where this leaves v1.3 Now we can: store strings compare strings print strings inspect length index into them as char This should make it much easier to replace the builtin C functions with a Flower library in the near-near future."}, {"post_id": 10953, "ts": "2026-06-17T23:26:21Z", "hours": 3.3353, "text": "Devlog: Finishing Flower’s String Interop Bridge The last round got string into Flower as a real type. This round was about making that foundation actually work lol. The big problem was that once string became real, plain string literals started living in an in-between state: Flower wanted them to mean “Flower string,” but the compiler’s own source still has plenty of places that really mean “raw C string,” like: RED: @char = \"\\033[0;31m\" if not strcmp(arg, \"help\") or not strcmp(arg, \"h\"): ... end Those cases worked before only because everything was basically pretending string literals were already @char . Once that stopped being true, bootstrap started throwing a fit (my spoiled child). What changed The main fix was to make string literal lowering contextual instead of all-or-nothing. If a literal is being used as a real Flower string , it stays a string . If a literal is being used in a C interop position, it gets lowered as a C string instead. That meant tightening a few compiler rules so this kind of thing works cleanly again: name: string = \"Ivy\" as string raw: @char = name as @char if strcmp(raw, \"Ivy\") == 0: print(name) end I also fixed top-level declarations so globals like: RED: @char = \"\\033[0;31m\" no longer generate nonsense like: char * RED = (( flower_string ){ ... }); which, unsurprisingly, C does not appreciate. The subtle compiler bug The nastiest issue wasn’t even the globals. It was that builtin C calls like strcmp , strncmp , printf , snprintf , and friends are not real Flower functions. That meant the typechecker could hit one of them inside a larger expression, fail early, and stop walking the rest of the tree. So something like: if not strcmp(arg, \"help\") or not strcmp(arg, \"h\"): could partially resolve one side, then leave the other side unprocessed. Very cool. Very stable. Definitely what I wanted. The fix was to add a temporary builtin C-call bridge so the compiler can recognize these calls well enough to keep type resolution and literal lowering consistent during bootstrap. I’m not happy with this fix by any means, but due to the limitations of emitting C, it was the only solution I found that made sense at the time. Tests and examples Once that stopped exploding, I finally wired string testing into the normal types suite instead of leaving it commented out and pretending I’d “get back to it later.” The string tests now cover: string <-> @char casts string equality / inequality .length empty strings printing strings literal use in current interop cases And the full test suite passed with string included as a first-class part of Types on its first try . Now that’s what I like to see :D What this means This does not mean Flower’s long-term answer is “hardcode libc into the compiler forever.” It means Flower now has a temporary interop bridge that keeps self-hosting stable while string is worked on. The actual language semantics stay in Flower; the backend-specific weirdness is just being tolerated for now so progress does not stall. In the near, I’ll probably replace all of the necessary C libs with minimal Flower-equivalents. Where this leaves v1.3 At this point, the string foundation feels much sturdier. Not “done forever,” not backend-agnostic, and definitely not free of cursed bootstrap energy — but it works. The next work is no longer rescue work. It is actual forward work: string operations, stdlib basics, and eventually replacing this temporary C bridge with something cleaner when Flower grows past the C backend."}, {"post_id": 9012, "ts": "2026-06-15T01:03:21Z", "hours": 2.7858, "text": "Devlog: Building Flower’s String Type Foundation The core goal was to make this work in a meaningful, compiler-owned way: name: string = \"Ivy\" as string raw: @char = name as @char other: string = raw as string if name == other: print(\"same\\n\") end print(name.length) That meant Flower needed more than a typedef in generated C. It needed actual type rules, actual lowering rules, and I needed enough hairs on my head to not be bald after the amount of scares that occurred. What changed The first step was giving string real compiler support without going too far too fast. I added support for: explicit casts between string and @char string equality / inequality string.length runtime helpers in generated C for: flower_string_from_cstr(...) flower_string_eq(...) flower_print_string(...) That gave Flower a usable string foundation while still keeping literals conservative for self-hosting. Right now, string literals are not fully “native string values everywhere” yet; the compiler still uses explicit casts like \"Ivy\" as string as the safe bridge. The reason for this “safe bridge” is because when I got too ambitious, the compiler would break since everywhere @char was used with a string literal it’d break due to no implicity being allowed. I had to comment out the following new changes and keep the legacy support so it’d compile: else if ast.kind == AST_STRING_LIT: // fprintf(out, \"flowe_string_from_cst(\") // fprintf(out, \"%.*s\", ast.data._string.str_length, src + ast.data._string.str_start) // fprintf(out, \")\") // LEGACY CODE HERE and else if expr.kind == AST_STRING_LIT: // set_plain_type(out, TOKEN_STRING) // LEGACY CODE HERE return 1 The part that broke The most annoying issue was not string equality or .length . It was print . Originally, non-string print(...) was basically lowered like this: printf ( expr ); That only works when expr is already a C format string. So something like: print(name.length) generated invalid C: printf ( name . length ); The fix was to make print(...) type-aware. Typecheck now records the operand type, and codegen lowers print differently for string , @char , char , floats/doubles, and integer-like values. That sounds small, but it matters a lot: once string became real, print could no longer get away with pretending every printable value was already a C string. An Unsolved Bootstrap Mystery Somehow Flower’s bootstrap process was breaking, and it will probably break again. Despite the bootstrap requiring it to compile itself, somehow afterwords the binary could become corrupted. l-2: ~/Documents/GitHub/FloC % make bootstrap === Building new version === Compiled ./bin/Flower_new.c → ./bin/Flower_new === Testing new compiler === Compiled ./bin/Flower_test.c → ./bin/Flower_test Verified bootstrap build complete l-2: ~/Documents/GitHub/FloC % make bootstrap === Building new version === Luckily, I always make sure to keep a backup Flower bin stored under /bin/Flower_backup so I used that to compile the new binary and then it worked. Where this leaves v1.3 What still remains is the bigger ergonomic question: how fully native string literals should behave, and how to migrate the compiler’s own source to that world without setting bootstrap on fire again. I’m not sure yet how I want to approach this question, or what the goals for it should even be, but I guess I’ll have to find out soon enough! That is the next fight. But at least now, it is a fight on solid ground."}, {"post_id": 8529, "ts": "2026-06-14T05:55:45Z", "hours": 3.8414, "text": "Devlog: Making Bool Real Without Breaking Bootstrap The original goal, asper usual, was straightforward: before moving on to string , Flower needed bool to actually mean something semantically. Up to this point, boolean-ish behavior mostly worked by accident. Comparisons, conditions, returns, and general expression checking were still loose enough that the compiler could get away with treating a lot of things as “close enough,” especially since the C backend ultimately lowers bool to int anyway. That was not going to hold once v1.3 started leaning on richer typing. So this was about drawing a clean line between Flower semantics and C lowering. The Goal In Flower: bool should be its own real type comparisons and logical operators should produce bool arithmetic should not quietly accept bool implicit conversion should stay narrow and predictable explicit casting should remain available through as In C: bool can still lower to int That distinction ended up being the easy part. What Changed The typechecker now treats bool as a proper language type instead of an int-shaped placeholder. Condition checks were tightened so if , while , and not use condition-compatible rules. Arithmetic paths now reject boolean operands, and return / initializer / argument checking now runs through more explicit conversion rules. I also kept implicit widening one-directional: int -> float -> double while leaving narrowing conversions as explicit casts. The actual implementation of booleans and their typing, enforcement, and semantics was a breeze. It’s what came after that got me. What Actually Broke As usual, bootstrap had opinions. The stricter type work exposed older weaknesses that were easy to miss before (This is my coping): function argument checks needed array-to-pointer decay alias and module call lookup paths were too narrow unresolved calls could prevent nested expressions from being fully type-resolved that, in turn, broke some dot-access lowering and caused bad . vs -> emission in generated C So part of this checkpoint turned into compiler stabilization work rather than just bool semantics due to my crappy ‘temporary’ logic, error handling — or lack thereof, and impeccable ability to miss very important details. I’m an amazing programmer, if you couldn’t tell :p Result Flower now has a much firmer semantic base for bool, and the compiler is back to bootstrapping cleanly with those rules in place. That matters because this was really the floor for the next part of v1.3: string . And.. maybe I’ll fix the bootstrap process so it doesn’t blow up in my face again. Oh yea, forgot to mention that. The bootstrapper bootstrapped itself into this very broken parser state that refused to go away so I had to stash my changes, checkout the prior merge (detached), and then recompile manually and fix the parser. Toodles!"}, {"post_id": 6924, "ts": "2026-06-11T16:28:33Z", "hours": 1.3047, "text": "Devlog: Fixing the Typechecker After Bool Enforcement Getting bool into Flower exposed a reallyyyy annoying problem: the typechecker had a couple of tiny logic mistakes (I’m so good at this) which caused the bootstrap to blow up in my face and I ahd no idea why. At first the errors looked unrelated. The compiler started reporting huge numbers of mismatches across main.flo , lexer.flo , module.flo , typecheck.flo , and codegen.flo . I was so confused as to why out of nowhere 903 lines were reporting various typechecking errors when they shouldn’t be. As it turns out, types_match() was the culprit. The function had been inverted in a few places: Mismatched base types and pointer depths were returning success, while normal matching primitive types were falling through to failure. That made the new compiler think ordinary initializers, assignments, comparisons, and returns were all invalid. Once that was fixed, the remaining failures turned out to be a second real compiler bug: pointer arithmetic over arrays was decaying in the wrong direction. Expressions like: mods.modules + j env.structs + env.struct_count arr + 1 should produce pointer types. Instead, the typechecker was reducing pointer depth when arrays decayed, which made perfectly normal indexed access and table walking look type-invalid. So this dev session ended up doing three important things: fixed types_match(...) so actual matches succeed and actual mismatches fail preserved decimal compatibility for float / double matching fixed array-to-pointer decay in pointer arithmetic so compiler internals and examples resolve correctly again What made this especially annoying is that the symptoms looked much larger than the cause. A couple of bad returns in the typechecker created hundreds of downstream errors, and because Flower is self-hosting, that meant the compiler started rejecting its own source. After correcting those core issues, both bootstrap and the example test suite started working again. That is the real value of issues like this: not just “fewer errors,” but restoring (MY) trust in the compiler and its ability to enforce Flower’s rules and report issues. With that stable again, the path forward is much clearer: continue bool work from a solid base, then move on to the remaining numeric and string improvements without the whole compiler collapsing under one bad predicate."}, {"post_id": 6207, "ts": "2026-06-10T12:52:51Z", "hours": 4.0928, "text": "Devlog: Making Flower’s Bool Support Real Enough to Survive Bootstrap The goal sounded small at first: add proper boolean support, while still lowering booleans to integers in C. In practice, this turned into an overarching type-system problem (typical!). Flower had reached a point where bool could not just be a naming trick over 1 and 0 . The compiler itself needed to understand when an expression was semantically boolean, when it was integer, and when older bootstrap-era shortcuts were no longer valid. A lot of those shortcuts had survived because the backend lowers bool to int anyway. But self-hosting exposed a major issue: source-level typing and C lowering are not the same thing. Things like these started breaking: val: int = parser_peek(ps).kind == TOKEN_TRUE and helper predicates that returned comparison expressions from int -typed functions. So the checkpoint became: keep C lowering simple, but make Flower’s typechecker treat booleans as a real source-level type. The main changes were: parser -> typecheck -> codegen true / false now parse into AST_BOOL_LIT bool literals are still emitted as 0 / 1 in C logical and comparison expressions now resolve to bool arithmetic rejects bool operands if , while , and not now validate condition-compatible expressions variable initializers, assignments, and returns now check types more strictly One of the more annoying bugs turned out not to be “about bools” at all. When code like this failed inside the compiler: defined_structs[i].length emitted_imports[i].path the real problem was that for i in 0..count was never registering i in the type environment, so indexed access looked broken when really the loop variable itself had no known type. Once loop indices were typed as int , those field-access failures disappeared (yay!!). The result is a much better place to build from: bool is now semantically distinct in Flower it still lowers cleanly to integer values in generated C bootstrap works again the compiler is stricter without collapsing under its own source That makes the next step much easier: real string support, instead of trying to build strings on top of a type system that still half-thinks everything is an int ."}, {"post_id": 5369, "ts": "2026-06-09T03:37:15Z", "hours": 5.4503, "text": "Devlog: Giving Flower Real Module Support v1.2.x was the point where Flower’s impors had to stop being “you can import stuff.. and there’s a fake layer of security” to a prop er (get it?) module system. Before this work, imports and aliases mostly behaved like naming conveniences. You could write: import \"math.flo\" as math math.add(1, 2) but the compiler was still too loose about what that really meant . Alias names were in emitted C symbol names, top-level declarations were not private, and prop existed more as syntax than as a real feature. That was fine for early bootstrap work, but it was not strong enough for the next stage of the language. So the main goal of v1.2.x became: make imported aliases act like real namespaces make prop define the public interface of a module make top-level declarations private by default lay groundwork for field visibility rules like hidden and readonly Module Semantics Instead of Alias Tricks One of the biggest changes was separating Flower semantics from C lowering. Previously, imported aliases were drifting toward becoming part of emitted symbol identity. A local alias should just be a source-level name bound to a module, not the backend symbol. So now each module has its own lowered symbol prefix, and alias lookup happens semantically during compilation. That means: import \"math.flo\" as math math.add(1, 2) is resolved as “look up exported add in module math.flo ,” not “invent a C symbol from the local alias text as math_add() .” That change also forced a cleanup of emitted names so they stopped leaking absolute filesystem paths. Generated symbols now use project-relative module prefixes instead of machine-specific paths. prop Became Real Another major part of this was making prop actually do something. Instead of treating it as a thin wrapper around only functions, the compiler now recognizes prop as a real top-level export marker. That means the module’s public interface is defined by what it explicitly exports, while non- prop declarations remain internal. This moved Flower closer to the model I wanted all along: explicit modules, explicit public APIs, no heavy object system (OOP), no fake privacy delegated to the C backend. Dot Access, Pointers, and the Annoying Middle Part This work also exposed a weakness in the compiler’s dot-access resolution. Flower source always uses . , while the C backend must decide whether a given access becomes . or -> . That mostly worked already, but nested pointer-heavy field chains exposed cases where the type tracker was not propagating enough information, which caused bad fallback behavior during self-hosting. So before field visibility could be trusted, I had to harden nested dot-access resolution. Not fun, but necessary. As it turns out, I was missing several AST kinds which caused the logic to fall through. Very tedious work, but it was well-worth it in the end! Field Flags Groundwork With module ownership and access resolution in better shape, I added the first field visibility modifiers: hidden readonly frozen Originally I debated having these as bitwise operations, but I decided it’d be best to stay within the current update’s scope, so sometime in the future I’ll refactor. Right now, hidden and readonly are the meaningful additions: hidden blocks external field access readonly blocks external assignment frozen is groundwork for later. It is parsed, stored, and carried through the compiler, but full assignment-once enforcement is still deferred. Unsure how I’ll go about it, but that’s an issue for future me :p"}, {"post_id": 4525, "ts": "2026-06-07T21:22:43Z", "hours": 3.6428, "text": "Devlog: Replacing Flower’s Old Function Syntax with func name(...): type This feature started out as what I thought would be a straightforward syntax cleanup. Flower’s old function syntax looked like this: int add(a: int, b: int): return a + b end and exported functions looked like this: prop int test(): return 1 end It worked, technically, but it had started to annoy me more. The biggest issue was that function declarations did not visually match the direction Flower was already heading in, and instead felt much more C-like than I wanted. prop func create(...): Person func main(): int This style says “this is a function” up front, gives a clean place for modifiers like prop , and keeps the return type attached to the signature rather than awkwardly leading it. The goal was simple: func name(...): type instead of: type name(...): Simple in theory. not so much when the compiler is written in the language being refactored. The Problem Flower’s parser assumes top-level function definitions start with a type. Old parser logic was built around that: int main(): means: parse a type, an identifier, params, and a body That assumption was scattered through a few different places: normal function definitions prop function declarations forward declarations examples and docs the compiler’s own source Now, in retrospect, this was actually one of the easier changes. It didn’t take a whole lot of planning nor brain power, and I was able to change it pretty quickly. Luckily for me, I’ve built codegen to rely purely on ast values rather than shaping. The New Shape The new syntax is: func add(a: int, b: int): int return a + b end and exported functions now look like: prop func test(): int return 1 end This is nicer because: func makes declarations immediately recognizable prop composes more cleanly with func return types now live where people expect them to future syntax has more room to grow without feeling backwards It also feels more in line with Flower’s broader goals: explicit, readable, and not complex. The Refactor Previously, parse_func_def looked for a return type first: type name(...): Now it expects: func name(...): type So the order changed to: expect func parse function name parse parameter list expect : parse return type parse body until end That part was conceptually easy. The more annoying part was updating all the places that assumed if it isn’t a var decl and it looks like a func, it’s a func. That fallback had to go (Good riddance!). Instead, top-level parsing needed to become more explicit: prop func → exported function func → normal function forward func → forward declaration The old one worked, but it relied on vague “anything else is probably a function” rules. The Bootstrap Mistake At one point, I made a bootstrap build so I could use a Flower_new binary to compile the refactored compiler. Unfortunately, I had made a mistake in parse_forward : advancing before peek checks. Feel free to check out the bootstrapper to see why this was an issue ;) This meant my “new compiler to compile the new compiler” was built from a broken parser. The workaround was cursed, but it worked : check out the commit before the refactor fix the bug compile a new binary switch to the refactor branch use the binary to compile the new version Since the compiled binary was ignored by Git, this was actually fairly simple. Not the most elegant bootstrap story, but it got the compiler to, well, compile."}, {"post_id": 3962, "ts": "2026-06-07T03:08:31Z", "hours": 8.2967, "text": "Devlog: Making Flower’s Type Tracking “Enough” for Stdlib / String Work The original motivation was simple and — supposedly — quick; I wanted to move on to v1.1.1 , “stdlib basics,” especially string utilities. But Flower’s current compiler did not really know what types expressions had. It mostly had pointer_depth on declarations, which was enough to generate * in C types and sometimes guess whether field access should become . or -> . That worked for very simple cases: p: @Vector2 = new Vector2 p.x = 5 But it broke down for nested access: outer.inner.value outer.inner_ptr.value The compiler could see the syntax chain, but it did not know whether inner was a value field or pointer field. Since Flower source only uses . , the C backend needs to decide whether each hop becomes . or -> . That meant stdlib work was blocked. If I want something like: if strings.equal(string_a, string_b): print(\"same\\n\") end then Flower needs to understand that string_a.length , string_a.data , etc. are real typed fields, not just random syntax to dump into C. Originally I thought I could just simply create a Symbol Table to get that to work. Unfortunately, that plan soon failed as it introduced a mariad of issues relating to the import system. At the time, this frustrated me because I knew the import system sucked, but I didn’t want to fix it until a later version. Eventually, I settled on a specific plan which did actually end up changing how imports are handled.. kinda. The Plan The design I landed on was to add a typecheck/type-tracking stage between parsing and codegen: lexer -> parser -> typecheck -> codegen The parser should stay mostly syntax-only. It builds AST nodes like “dot access,” so I didn’t really change it. The typecheck pass now collects declarations into a TypeEnv : struct TypeEnv { structs: StructInfo[1024], struct_count: int, vars: VarInfo[8192], var_count: int, funcs: FuncInfo[8192], func_count: int, error_count: int } Then it walks expressions and annotates dot access nodes with an access kind: ACCESS_UNKNOWN: int = 0 ACCESS_DOT: int = 1 ACCESS_ARROW: int = 2 So codegen no longer has to fully guess. It can do: if ast.data._dot_access.access_kind == ACCESS_ARROW: fprintf(out, \"->%.*s\", ...) else if ast.data._dot_access.access_kind == ACCESS_DOT: fprintf(out, \".%.*s\", ...) else: // fallback end That fallback is important because Flower is self-hosted-ish right now. The compiler is written in Flower, and the compiler’s own source code is full of field access. If the new typechecker is too strict too early, it breaks the compiler while trying to compile the compiler. Very elegant. Very cursed. Just how I like it ;) Import-Aware Type Tracking At first, typechecking only saw the main file, so I added a module loading pass. Instead of codegen discovering and parsing imports late, the compiler now loads modules earlier: load main module load imports recursively collect declarations from all modules typecheck all modules codegen all modules That required a new module structure: struct Module { path: @char, src: @char, tokens: @TokenStream, ast: @AST } struct ModuleSet { modules: Module[128], count: int } Unfortunately, it didn’t go as smoothly as I wanted. Near the end when I was sure everything would work, I ran into an Idempotency failure due to the new handling of system imports. I.. just manually passed it :p"}]...
|
Title: Flower by @IvyMycelia | Stardance
Devlogs: Title: Flower by @IvyMycelia | Stardance
Devlogs:
Devlog: Making Flower’s Type Tracking “Enough” for Stdlib / String Work The original motivation was simple and — supposedly — quick; I wanted to move on to v1.1.1 , “stdlib basics,” especially string utilities. But Flower’s current compiler did not really know what types expressions had. It mostly had pointer_depth on declarations, which was enough to generate * in C types and sometimes guess whether field access should become . or -> . That worked for very simple cases: p: @Vector2 = new Vector2 p.x = 5 But it broke down for nested access: outer.inner.value outer.inner_ptr.value The compiler could see the syntax chain, but it did not know whether inner was a value field or pointer field. Since Flower source only uses . , the C backend needs to decide whether each hop becomes . or -> . That meant stdlib work was blocked. If I want something like: if strings.equal(string_a, string_b): print("same\n") end then Flower needs to understand that string_a.length , string_a.data , etc. are real typed fields, not just random syntax to dump into C. Originally I thought I could just simply create a Symbol Table to get that to work. Unfortunately, that plan soon failed as it introduced a mariad of issues relating to the import system. At the time, this frustrated me because I knew the import system sucked, but I didn’t want to fix it until a later version. Eventually, I settled on a specific plan which did actually end up changing how imports are handled.. kinda. The Plan The design I landed on was to add a typecheck/type-tracking stage between parsing and codegen: lexer -> parser -> typecheck -> codegen The parser should stay mostly syntax-only. It builds AST nodes like “dot access,” so I didn’t really change it. The typecheck pass now collects declarations into a TypeEnv : struct TypeEnv { structs: StructInfo[1024], struct_count: int, vars: VarInfo[8192], var_count: int, funcs: FuncInfo[8192], func_count: int, error_count: int } Then it walks expressions and annotates dot access nodes with an access kind: ACCESS_UNKNOWN: int = 0 ACCESS_DOT: int = 1 ACCESS_ARROW: int = 2 So codegen no longer has to fully guess. It can do: if ast.data._dot_access.access_kind == ACCESS_ARROW: fprintf(out, "->%.*s", ...) else if ast.data._dot_access.access_kind == ACCESS_DOT: fprintf(out, ".%.*s", ...) else: // fallback end That fallback is important because Flower is self-hosted-ish right now. The compiler is written in Flower, and the compiler’s own source code is full of field access. If the new typechecker is too strict too early, it breaks the compiler while trying to compile the compiler. Very elegant. Very cursed. Just how I like it ;) Import-Aware Type Tracking At first, typechecking only saw the main file, so I added a module loading pass. Instead of codegen discovering and parsing imports late, the compiler now loads modules earlier: load main module load imports recursively collect declarations from all modules typecheck all modules codegen all modules That required a new module structure: struct Module { path: @char, src: @char, tokens: @TokenStream, ast: @AST } struct ModuleSet { modules: Module[128], count: int } Unfortunately, it didn’t go as smoothly as I wanted. Near the end when I was sure everything would work, I ran into an Idempotency failure due to the new handling of system imports. I.. just manually passed it :p
Devlog: Replacing Flower’s Old Function Syntax with func name(...): type This feature started out as what I thought would be a straightforward syntax cleanup. Flower’s old function syntax looked like this: int add(a: int, b: int): return a + b end and exported functions looked like this: prop int test(): return 1 end It worked, technically, but it had started to annoy me more. The biggest issue was that function declarations did not visually match the direction Flower was already heading in, and instead felt much more C-like than I wanted. prop func create(...): Person func main(): int This style says “this is a function” up front, gives a clean place for modifiers like prop , and keeps the return type attached to the signature rather than awkwardly leading it. The goal was simple: func name(...): type instead of: type name(...): Simple in theory. not so much when the compiler is written in the language being refactored. The Problem Flower’s parser assumes top-level function definitions start with a type. Old parser logic was built around that: int main(): means: parse a type, an identifier, params, and a body That assumption was scattered through a few different places: normal function definitions prop function declarations forward declarations examples and docs the compiler’s own source Now, in retrospect, this was actually one of the easier changes. It didn’t take a whole lot of planning nor brain power, and I was able to change it pretty quickly. Luckily for me, I’ve built codegen to rely purely on ast values rather than shaping. The New Shape The new syntax is: func add(a: int, b: int): int return a + b end and exported functions now look like: prop func test(): int return 1 end This is nicer because: func makes declarations immediately recognizable prop composes more cleanly with func return types now live where people expect them to future syntax has more room to grow without feeling backwards It also feels more in line with Flower’s broader goals: explicit, readable, and not complex. The Refactor Previously, parse_func_def looked for a return type first: type name(...): Now it expects: func name(...): type So the order changed to: expect func parse function name parse parameter list expect : parse return type parse body until end That part was conceptually easy. The more annoying part was updating all the places that assumed if it isn’t a var decl and it looks like a func, it’s a func. That fallback had to go (Good riddance!). Instead, top-level parsing needed to become more explicit: prop func → exported function func → normal function forward func → forward declaration The old one worked, but it relied on vague “anything else is probably a function” rules. The Bootstrap Mistake At one point, I made a bootstrap build so I could use a Flower_new binary to compile the refactored compiler. Unfortunately, I had made a mistake in parse_forward : advancing before peek checks. Feel free to check out the bootstrapper to see why this was an issue ;) This meant my “new compiler to compile the new compiler” was built from a broken parser. The workaround was cursed, but it worked : check out the commit before the refactor fix the bug compile a new binary switch to the refactor branch use the binary to compile the new version Since the compiled binary was ignored by Git, this was actually fairly simple. Not the most elegant bootstrap story, but it got the compiler to, well, compile.
Devlog: Giving Flower Real Module Support v1.2.x was the point where Flower’s impors had to stop being “you can import stuff.. and there’s a fake layer of security” to a prop er (get it?) module system. Before this work, imports and aliases mostly behaved like naming conveniences. You could write: import "math.flo" as math math.add(1, 2) but the compiler was still too loose about what that really meant . Alias names were in emitted C symbol names, top-level declarations were not private, and prop existed more as syntax than as a real feature. That was fine for early bootstrap work, but it was not strong enough for the next stage of the language. So the main goal of v1.2.x became: make imported aliases act like real namespaces make prop define the public interface of a module make top-level declarations private by default lay groundwork for field visibility rules like hidden and readonly Module Semantics Instead of Alias Tricks One of the biggest changes was separating Flower semantics from C lowering. Previously, imported aliases were drifting toward becoming part of emitted symbol identity. A local alias should just be a source-level name bound to a module, not the backend symbol. So now each module has its own lowered symbol prefix, and alias lookup happens semantically during compilation. That means: import "math.flo" as math math.add(1, 2) is resolved as “look up exported add in module math.flo ,” not “invent a C symbol from the local alias text as math_add() .” That change also forced a cleanup of emitted names so they stopped leaking absolute filesystem paths. Generated symbols now use project-relative module prefixes instead of machine-specific paths. prop Became Real Another major part of this was making prop actually do something. Instead of treating it as a thin wrapper around only functions, the compiler now recognizes prop as a real top-level export marker. That means the module’s public interface is defined by what it explicitly exports, while non- prop declarations remain internal. This moved Flower closer to the model I wanted all along: explicit modules, explicit public APIs, no heavy object system (OOP), no fake privacy delegated to the C backend. Dot Access, Pointers, and the Annoying Middle Part This work also exposed a weakness in the compiler’s dot-access resolution. Flower source always uses . , while the C backend must decide whether a given access becomes . or -> . That mostly worked already, but nested pointer-heavy field chains exposed cases where the type tracker was not propagating enough information, which caused bad fallback behavior during self-hosting. So before field visibility could be trusted, I had to harden nested dot-access resolution. Not fun, but necessary. As it turns out, I was missing several AST kinds which caused the logic to fall through. Very tedious work, but it was well-worth it in the end! Field Flags Groundwork With module ownership and access resolution in better shape, I added the first field visibility modifiers: hidden readonly frozen Originally I debated having these as bitwise operations, but I decided it’d be best to stay within the current update’s scope, so sometime in the future I’ll refactor. Right now, hidden and readonly are the meaningful additions: hidden blocks external field access readonly blocks external assignment frozen is groundwork for later. It is parsed, stored, and carried through the compiler, but full assignment-once enforcement is still deferred. Unsure how I’ll go about it, but that’s an issue for future me :p
Devlog: Making Flower’s Bool Support Real Enough to Survive Bootstrap The goal sounded small at first: add proper boolean support, while still lowering booleans to integers in C. In practice, this turned into an overarching type-system problem (typical!). Flower had reached a point where bool could not just be a naming trick over 1 and 0 . The compiler itself needed to understand when an expression was semantically boolean, when it was integer, and when older bootstrap-era shortcuts were no longer valid. A lot of those shortcuts had survived because the backend lowers bool to int anyway. But self-hosting exposed a major issue: source-level typing and C lowering are not the same thing. Things like these started breaking: val: int = parser_peek(ps).kind == TOKEN_TRUE and helper predicates that returned comparison expressions from int -typed functions. So the checkpoint became: keep C lowering simple, but make Flower’s typechecker treat booleans as a real source-level type. The main changes were: parser -> typecheck -> codegen true / false now parse into AST_BOOL_LIT bool literals are still emitted as 0 / 1 in C logical and comparison expressions now resolve to bool arithmetic rejects bool operands if , while , and not now validate condition-compatible expressions variable initializers, assignments, and returns now check types more strictly One of the more annoying bugs turned out not to be “about bools” at all. When code like this failed inside the compiler: defined_structs[i].length emitted_imports[i].path the real problem was that for i in 0..count was never registering i in the type environment, so indexed access looked broken when really the loop variable itself had no known type. Once loop indices were typed as int , those field-access failures disappeared (yay!!). The result is a much better place to build from: bool is now semantically distinct in Flower it still lowers cleanly to integer values in generated C bootstrap works again the compiler is stricter without collapsing under its own source That makes the next step much easier: real string support, instead of trying to build strings on top of a type system that still half-thinks everything is an int .
Devlog: Fixing the Typechecker After Bool Enforcement Getting bool into Flower exposed a reallyyyy annoying problem: the typechecker had a couple of tiny logic mistakes (I’m so good at this) which caused the bootstrap to blow up in my face and I ahd no idea why. At first the errors looked unrelated. The compiler started reporting huge numbers of mismatches across main.flo , lexer.flo , module.flo , typecheck.flo , and codegen.flo . I was so confused as to why out of nowhere 903 lines were reporting various typechecking errors when they shouldn’t be. As it turns out, types_match() was the culprit. The function had been inverted in a few places: Mismatched base types and pointer depths were returning success, while normal matching primitive types were falling through to failure. That made the new compiler think ordinary initializers, assignments, comparisons, and returns were all invalid. Once that was fixed, the remaining failures turned out to be a second real compiler bug: pointer arithmetic over arrays was decaying in the wrong direction. Expressions like: mods.modules + j env.structs + env.struct_count arr + 1 should produce pointer types. Instead, the typechecker was reducing pointer depth when arrays decayed, which made perfectly normal indexed access and table walking look type-invalid. So this dev session ended up doing three important things: fixed types_match(...) so actual matches succeed and actual mismatches fail preserved decimal compatibility for float / double matching fixed array-to-pointer decay in pointer arithmetic so compiler internals and examples resolve correctly again What made this especially annoying is that the symptoms looked much larger than the cause. A couple of bad returns in the typechecker created hundreds of downstream errors, and because Flower is self-hosting, that meant the compiler started rejecting its own source. After correcting those core issues, both bootstrap and the example test suite started working again. That is the real value of issues like this: not just “fewer errors,” but restoring (MY) trust in the compiler and its ability to enforce Flower’s rules and report issues. With that stable again, the path forward is much clearer: continue bool work from a solid base, then move on to the remaining numeric and string improvements without the whole compiler collapsing under one bad predicate.
Devlog: Making Bool Real Without Breaking Bootstrap The original goal, asper usual, was straightforward: before moving on to string , Flower needed bool to actually mean something semantically. Up to this point, boolean-ish behavior mostly worked by accident. Comparisons, conditions, returns, and general expression checking were still loose enough that the compiler could get away with treating a lot of things as “close enough,” especially since the C backend ultimately lowers bool to int anyway. That was not going to hold once v1.3 started leaning on richer typing. So this was about drawing a clean line between Flower semantics and C lowering. The Goal In Flower: bool should be its own real type comparisons and logical operators should produce bool arithmetic should not quietly accept bool implicit conversion should stay narrow and predictable explicit casting should remain available through as In C: bool can still lower to int That distinction ended up being the easy part. What Changed The typechecker now treats bool as a proper language type instead of an int-shaped placeholder. Condition checks were tightened so if , while , and not use condition-compatible rules. Arithmetic paths now reject boolean operands, and return / initializer / argument checking now runs through more explicit conversion rules. I also kept implicit widening one-directional: int -> float -> double while leaving narrowing conversions as explicit casts. The actual implementation of booleans and their typing, enforcement, and semantics was a breeze. It’s what came after that got me. What Actually Broke As usual, bootstrap had opinions. The stricter type work exposed older weaknesses that were easy to miss before (This is my coping): function argument checks needed array-to-pointer decay alias and module call lookup paths were too narrow unresolved calls could prevent nested expressions from being fully type-resolved that, in turn, broke some dot-access lowering and caused bad . vs -> emission in generated C So part of this checkpoint turned into compiler stabilization work rather than just bool semantics due to my crappy ‘temporary’ logic, error handling — or lack thereof, and impeccable ability to miss very important details. I’m an amazing programmer, if you couldn’t tell :p Result Flower now has a much firmer semantic base for bool, and the compiler is back to bootstrapping cleanly with those rules in place. That matters because this was really the floor for the next part of v1.3: string . And.. maybe I’ll fix the bootstrap process so it doesn’t blow up in my face again. Oh yea, forgot to mention that. The bootstrapper bootstrapped itself into this very broken parser state that refused to go away so I had to stash my changes, checkout the prior merge (detached), and then recompile manually and fix the parser. Toodles!
Devlog: Building Flower’s String Type Foundation The core goal was to make this work in a meaningful, compiler-owned way: name: string = "Ivy" as string raw: @char = name as @char other: string = raw as string if name == other: print("same\n") end print(name.length) That meant Flower needed more than a typedef in generated C. It needed actual type rules, actual lowering rules, and I needed enough hairs on my head to not be bald after the amount of scares that occurred. What changed The first step was giving string real compiler support without going too far too fast. I added support for: explicit casts between string and @char string equality / inequality string.length runtime helpers in generated C for: flower_string_from_cstr(...) flower_string_eq(...) flower_print_string(...) That gave Flower a usable string foundation while still keeping literals conservative for self-hosting. Right now, string literals are not fully “native string values everywhere” yet; the compiler still uses explicit casts like "Ivy" as string as the safe bridge. The reason for this “safe bridge” is because when I got too ambitious, the compiler would break since everywhere @char was used with a string literal it’d break due to no implicity being allowed. I had to comment out the following new changes and keep the legacy support so it’d compile: else if ast.kind == AST_STRING_LIT: // fprintf(out, "flowe_string_from_cst(") // fprintf(out, "%.*s", ast.data._string.str_length, src + ast.data._string.str_start) // fprintf(out, ")") // LEGACY CODE HERE and else if expr.kind == AST_STRING_LIT: // set_plain_type(out, TOKEN_STRING) // LEGACY CODE HERE return 1 The part that broke The most annoying issue was not string equality or .length . It was print . Originally, non-string print(...) was basically lowered like this: printf ( expr ); That only works when expr is already a C format string. So something like: print(name.length) generated invalid C: printf ( name . length ); The fix was to make print(...) type-aware. Typecheck now records the operand type, and codegen lowers print differently for string , @char , char , floats/doubles, and integer-like values. That sounds small, but it matters a lot: once string became real, print could no longer get away with pretending every printable value was already a C string. An Unsolved Bootstrap Mystery Somehow Flower’s bootstrap process was breaking, and it will probably break again. Despite the bootstrap requiring it to compile itself, somehow afterwords the binary could become corrupted. l-2: ~/Documents/GitHub/FloC % make bootstrap === Building new version === Compiled ./bin/Flower_new.c → ./bin/Flower_new === Testing new compiler === Compiled ./bin/Flower_test.c → ./bin/Flower_test Verified bootstrap build complete l-2: ~/Documents/GitHub/FloC % make bootstrap === Building new version === Luckily, I always make sure to keep a backup Flower bin stored under /bin/Flower_backup so I used that to compile the new binary and then it worked. Where this leaves v1.3 What still remains is the bigger ergonomic question: how fully native string literals should behave, and how to migrate the compiler’s own source to that world without setting bootstrap on fire again. I’m not sure yet how I want to approach this question, or what the goals for it should even be, but I guess I’ll have to find out soon enough! That is the next fight. But at least now, it is a fight on solid ground.
Devlog: Finishing Flower’s String Interop Bridge The last round got string into Flower as a real type. This round was about making that foundation actually work lol. The big problem was that once string became real, plain string literals started living in an in-between state: Flower wanted them to mean “Flower string,” but the compiler’s own source still has plenty of places that really mean “raw C string,” like: RED: @char = "\033[0;31m" if not strcmp(arg, "help") or not strcmp(arg, "h"): ... end Those cases worked before only because everything was basically pretending string literals were already @char . Once that stopped being true, bootstrap started throwing a fit (my spoiled child). What changed The main fix was to make string literal lowering contextual instead of all-or-nothing. If a literal is being used as a real Flower string , it stays a string . If a literal is being used in a C interop position, it gets lowered as a C string instead. That meant tightening a few compiler rules so this kind of thing works cleanly again: name: string = "Ivy" as string raw: @char = name as @char if strcmp(raw, "Ivy") == 0: print(name) end I also fixed top-level declarations so globals like: RED: @char = "\033[0;31m" no longer generate nonsense like: char * RED = (( flower_string ){ ... }); which, unsurprisingly, C does not appreciate. The subtle compiler bug The nastiest issue wasn’t even the globals. It was that builtin C calls like strcmp , strncmp , printf , snprintf , and friends are not real Flower functions. That meant the typechecker could hit one of them inside a larger expression, fail early, and stop walking the rest of the tree. So something like: if not strcmp(arg, "help") or not strcmp(arg, "h"): could partially resolve one side, then leave the other side unprocessed. Very cool. Very stable. Definitely what I wanted. The fix was to add a temporary builtin C-call bridge so the compiler can recognize these calls well enough to keep type resolution and literal lowering consistent during bootstrap. I’m not happy with this fix by any means, but due to the limitations of emitting C, it was the only solution I found that made sense at the time. Tests and examples Once that stopped exploding, I finally wired string testing into the normal types suite instead of leaving it commented out and pretending I’d “get back to it later.” The string tests now cover: string <-> @char casts string equality / inequality .length empty strings printing strings literal use in current interop cases And the full test suite passed with string included as a first-class part of Types on its first try . Now that’s what I like to see :D What this means This does not mean Flower’s long-term answer is “hardcode libc into the compiler forever.” It means Flower now has a temporary interop bridge that keeps self-hosting stable while string is worked on. The actual language semantics stay in Flower; the backend-specific weirdness is just being tolerated for now so progress does not stall. In the near, I’ll probably replace all of the necessary C libs with minimal Flower-equivalents. Where this leaves v1.3 At this point, the string foundation feels much sturdier. Not “done forever,” not backend-agnostic, and definitely not free of cursed bootstrap energy — but it works. The next work is no longer rescue work. It is actual forward work: string operations, stdlib basics, and eventually replacing this temporary C bridge with something cleaner when Flower grows past the C backend.
Devlog: Adding String Indexing to Flower This one was fairly quick, and was about making one very normal-looking thing actually work: name: string = "Ivy" as string first: char = name[0] That sounds small, but once string became a real Flower type, indexing could no longer piggyback on the old “arrays and pointers only” behavior. The compiler needed to understand that string[index] is its own case. What changed I taught the typechecker to treat string subscripts as char . That means: string[index] now resolves to char the index expression must be an integer string indexing is readonly for now So this is valid: first: char = name[0] but this is not: name[0] = 'X' I wanted reads first, writes later. That keeps the rules simple while the string representation is still compiler-owned. I’m not sure how writes would work with a C backend, due to how ‘strings’ are allocated. Perhaps a feature for post-v2.0? Lowering it to C Since Flower strings currently lower to a struct with .data and .length , codegen needed a special path for string subscripts. Normal arrays and pointers still lower like: arr [ index ] but strings now lower like: name . data [ index ] That keeps the generated C valid without changing how regular subscripts work elsewhere in the language. So something conceptually like: This checkpoint also forced one strict-but-correct rule that required me to update a WHOLE SINGLE LINE (hehe): arg[i] = tolower(arg[i] as char) to arg[i] = tolower(arg[i] as char) as char Because tolower(...) is effectively treated as returning int , assigning it back into a char subscript needs an explicit cast. I kept that strictness on purpose. I do not want Flower silently narrowing values just because C would let it. Validation I expanded the string example coverage to check: string indexing returns the expected chars string[index] works alongside string <-> @char casts bootstrap still succeeds repeated bootstrap succeeds tests still pass Which, after all the recent bootstrap chaos, was very nice to see. Where this leaves v1.3 Now we can: store strings compare strings print strings inspect length index into them as char This should make it much easier to replace the builtin C functions with a Flower library in the near-near future.
Devlog: Fixing Flower’s Output Driver and Starting the String Stdlib This checkpoint was really two different kinds of progress that ended up helping each other a lot. The first part was not glamorous, but it was necessary: Flower’s compile driver was tripping over its own default output naming. This was a known issue that I had been putting off, but for some reason it really annoyed me this time so I decided enough and to fix it. If no explicit output path was provided, the compiler would generate output.c , then strip the .c and try to emit a binary named output . That worked fine right up until the repo itself already had an output/ directory. At that point, linking failed because the compiler was trying to create a file where a directory already existed. Worse — because it annoyed me more — the driver logic was also mixing up “the generated program exited non-zero” with “compilation failed.” That became especially annoying during bootstrap, because the generated compiler binary would run without CLI arguments, print its own usage error, and then cause bootstrap to report failure even though codegen and C compilation had both succeeded. So I finally got off my butt and cleaned that up. Driver Cleanup The default output path now goes to: output/out.c which naturally produces: output/out as the binary. That avoids the old output filename collision. I also separated compile success from auto-run behavior: explicit output path: compile only default output path: compile, then auto-run if appropriate That means bootstrap no longer “fails” just because the compiled compiler exits non-zero with missing arguments, and demo/test files can still run automatically when that is actually useful. This sounds like a small driver fix, but honestly it removed a lot of noise from string work — and more — immediately. String Stdlib Beginnings Once that output weirdness was under control, I could finish doing what I just started and actually wanted: making string behavior live in Flower instead of endlessly leaning on ad hoc C calls (Call back to last devlog, absolute ball knowledge!!). So I added the first real reusable helpers in src/stdlib/string.flo : is_empty(s) starts_with(s, prefix) ends_with(s, suffix) find_char(s, ch) These are intentionally simple. They mostly exist to prove that the current string support is now strong enough for normal library code to be written on top of it. Not incredibly useful, at least at the level the compiler needs, but at least I could translate some AP Comp Sci A into Flower hehe A string feature does not really feel “real” until I can build helpers with the language itself instead of only teaching the compiler more special cases. The day I remove the builtin C handlers is the day I’m at peace… Validation To exercise that new library surface, I changed string_pass.flo to now act as a small pass file for the experimental library. Its job is not to be impressive. Its job is to answer a more important question: can I import string helpers, call them from normal Flower code, and get expected results through the full compile pipeline? At this point, yes. Where this leaves things This checkpoint did not remove all C string dependencies from the compiler. In fact, it removed essentially none! That is still a separate step, one that may even be in v1.3.7 ;) But it did establish two important things: Flower’s output/driver behavior is now much less annoying. We can start growing a real string library in Flower itself. That is a good place to be, because the next string work can build outward from a stable driver and an actual library surface instead of piling more special behavior into the compiler.
Devlog: Giving Flower an Internal cstr Foundation Even after Flower got a real string type, the compiler itself was still leaning directly on C-style string helpers for its own internal work. That meant a lot of Flower source was still semantically depending on libc behavior: !strncmp(...) strcmp(...) strlen(...) strcpy(...) strncpy(...) strdup(...) strrchr(...) That is not where I want the language to stay. What changed I added a new internal module: import "src/stdlib/cstr.flo" as cstr and gave it compiler-facing helpers like: prop func len(s: @char): int prop func eq(a: @char, b: @char): bool prop func eq_n(a: @char, b: @char, n: int): bool prop func copy(dst: @char, src: @char): @char prop func copy_n(dst: @char, src: @char, n: int): @char prop func dup(src: @char): @char prop func find_last(src: @char, ch: char): @char This helper module is essentially the precursor to a future strings.flo library that can be distributed. But for now, it uses a basic API layer purely meant for in-house usage. Then I migrated compiler internals over to that module across: src/parser.flo src/module.flo src/lexer.flo src/typecheck.flo src/codegen.flo src/globals.flo src/main.flo So instead of using C-string behavior directly everywhere, the compiler now goes through Flower-owned helpers first. The Compiler Strikes Back This was one of those changes that sounds mechanical until it absolutely is not. A big trap was that old code often relied on C comparison functions returning 0 on equality, so patterns looked like this: not strncmp(...) But cstr.eq_n(...) returns an actual bool , which means blindly rewriting those calls gives inverted logic. So this: if ps.alias_lengths[i] == tok.length and not cstr.eq_n(...): was completely wrong. It had to become: if ps.alias_lengths[i] == tok.length and cstr.eq_n(...): That bug showed up in alias parsing first, which made it especially cursed, because it caused normal namespace-style calls like cstr.eq(...) to stop parsing correctly and crash the bootstrap path in confusing ways. I spent way longer than I wish to admit on trying to figure out why it wasn’t playing nice. But, once I figured it out, it was a really quick fix (I literally just cmd + f ’d not cstr and replaced it with cstr lol). Are we done yet..? This does not mean Flower is free from the C backend yet. It does mean something important, though: compiler logic is starting to depend on Flower-defined helper semantics instead of scattered raw libc calls. That is a much better stage for the future backend story, because when C eventually stops being the primary lowering target, the compiler will already have more of its own vocabulary. In other words, this was less about “remove C” and more about “stop letting C define the language’s internal habits.” Nah just kidding, I really wanted that bloated “builtin_c_call” stuff gone. Unfortunately I only managed to skim it, but that’s closer than before! Result After fixing the migration mistakes and the alias/parser fallout, the compiler bootstrapped successfully again. Flower now has an internal cstr layer, and compiler string handling is a little more its own.
Devlog: Cleaning Up v1.3 For Release After many hours of work, bool and `string finally became real, and it was time to cleanup the mess I left behind from the version’s development. Mainly the only thing worked on was some cleanup: roadmap now reflects actual v1.3 features and implementations updated README and contribution documents to match the current compiler pipeline cleaned up string examples so they have the full intended v1.3 style instead of some leftover testing usage pushed the compiler’s version to 1.3.0 updated help / usage text so it matches the new output-path and auto-run behavior Prior to this, if I had just merged and shipped, the release wouldv’e been messy: README, Contributing, example files, and guidance commands were all mixing older details which made it confusing — even for me — when trying to explore the language and what it has to offer. For a bootstrapped compiler especially, making sure everything is cleaned up and polished is something that should not be ignored. I’m definitely guilty of overlooking this, but I’ve outlayed a whole plan for v1.3 unlike past versions, and part of it was setting up a proper versioning system and polishing its release as it goes. This format will be adopted in future versions, since it’s just way cleaner and nicer to look at. Future work At this point, v1.3 is done and has implemented, at minimum, a concrete foundation for post-v2 bools and strings. Next will likely be more subtle improvements, and features that are currently reliant explicitly on C rather than Flower-hosted code. In order for v2.0 , Flower will have to be effectively independent from C if it wants to emit machine code. Currently I am planning on adding features such as Type Aliases and maybe a stdlib prior to that, but anything can change!! Thanks for being here for all of v1.3 <3
Devlog: Making Flower’s Type Aliases Transparent This version was simple to develop on paper (and even in practice it wasn’t too bad, only around 4 or so hours!): type Count = int type Total = Count type Name = string and then have those aliases behave like the real type everywhere: n: Count = 12 total: Total = identity(n) name: Name = "Ivy" if name != "Ivy": return false end if name.length != 3: return false end That meant aliases could not just be parsed and stored, but rather had to be transparent to the compiler’s semantic checks. What changed I added type alias declarations to the AST, parser, and type environment, then added the ability to resolve aliases in typechecking before comparing types. That included: return type checks variable initializers function call arguments binary comparisons string-specific comparison logic struct field access The important rule here is that aliases are semantic, not codegen-facing. Count should behave as int , Name should behave as string , and chained aliases like Total -> Count -> int should collapse correctly. In the future, especially post v2.0 , this could change and custom types might become real — but for now, they’re just aliases. The bug that exploded bootstrap The first real failure was not in aliases themselves, but in function argument checking. Inside check_call_args(...) , the compiler was resolving the argument expression into expected_type instead of arg_type . That overwrote the parameter type, left the actual argument type uninitialized, and caused the second bootstrap stage to explode into over a thousand misleading errors. This was not a pre-existing issue, it was instead from human error (my error) during the initial implementation where I accidentally put the wrong variable. Once that was fixed, the remaining failures were much more helpful than the bright flash of red and “Typecheck failed with 1224 error(s)” message! Where this leaves v1.4 With the first step toward “better types” done, aliases are no longer just syntax. That gives v1.4 a solid base for whatever comes next in the type system without having to fake around raw names. During this whole dev session, I did discover that a whole lot more of the source code was left using legacy work-arounds: int instead of bool , name_start; name_length and @char instead of string . In all fairness, some of these aren’t exactly the easiest to refactor. However, I will probably hold off on refactoring the codebase until either right before v2.0 , or right after. Just know it’s on my radar ;)
Devlog: Fixing Flower’s Compiler Process So It Stops Fighting the Host This wasn’t really about language design at all buttttt it is much more embarrassing , AND more important: Flower’s compiler process itself was too fragile. The immediate issue showed up on Linux, specifically NixOS (thanks shipwrights <3). The build flow was assuming too much: a previously existing bin/Flower could be reused safely bash would exist at the expected path clang would always be available the checked-in compiler binary would be runnable on whatever machine the repo landed on That worked well enough on my machine until it didn’t. On NixOS — and by extension probably any other machine without the prexisting binaries I had — it broke: make targets were inconsistent, the shell script failed on interpreter assumptions, and the compiler binary itself could be the wrong format for the host. What changed The fix was to separate “the compiler source exists” from “the current compiler binary is usable on this machine.” The build process now starts by compiling a fresh host-native bootstrap compiler from bin/Flower.c , instead of trusting whatever happens to already exist in bin/Flower . That means the flow is now: bin/Flower.c -> host-native bootstrap compiler -> new Flower compiler -> self-check instead of: maybe existing bin/Flower -> hopefully works -> maybe bootstrap Ok well that’s kinda a lie; it still relies on hopes and dreams to bootstrap sometimes. BUT it’s MUCH safer! And now everyone gets to experience crippling bootstrap anxiety, instead of being met with a failure before the actual compiler gets to.. well, do its thign! I also cleaned up the surrounding tooling: switched the bootstrap script to portable sh restored a clearer build / bootstrap / rebuild / test / clean structure made the compiler use CC and CFLAGS from the environment instead of hardcoding clang What this actually improves Flower is still not universally cross-platform yet. The compiler driver still has POSIX-shaped assumptions in places, and the emitted C can still depend on host APIs depending on what the program uses. I’m not yet at the point of wanting to make it completely universal, especially given how I’m only one person and with v2.0 coming up soon it’d — in my humblest of opinions — be a waste of time. I am honestly grateful for people reviewing my code and otherwise viewing it catching onto details I have overlooked. My goal is to not make a ‘just-barely working on my machine’ project; I enjoy sharing development with others, and it hurts knowing people can’t appreciate code, whether it be mine or others’, due to something as simple as hard-coded sh flags.
Devlog: Formalizing Flower’s Null Foundation Flower already had some of the pieces for null , but they were a bit scattered. The goal here was to make it explicit, consistent, and safe before moving on to nullable syntax like ?T or full union-based nullability later in v1.4 . Another shorter devlog, but still important and distinct enough for me to think “Hmm devlog time? Yes, devlog time!” What changed The main work was in typechecking. I added to the compiler’s idea of what null is, how it is represented internally, and what kinds of values are actually allowed to accept it. Rather than letting null-related behavior stay implicit across a few checks, null now follows a clearer rule set: null has one centralized internal type representation pointer-like values can explicitly accept null null comparisons and assignments now go through the same semantic path Why this matters This isn’t all that important on its own, but it matters a lot for where Flower is going next. If null is not defined well, then later features like: ?T better unions smarter narrowing more expressive type flow all become more error-prone (or so I assume given my track record) than I want need them to be. Validation I also expanded the example coverage so null : it now has dedicated behavior checks around assignment, passing values around, and comparison behavior.
Devlog: Adding Pointer-First Nullable Types to Flower I worked on giving Flower its first real nullable type surface without being overambitious and pretending the compiler is ready for full optional-everything semantics yet. The new syntax now works like this: ptr: ?@int = null text: ?@char = null That means there is now an explicit way to say “this pointer-like value may be absent,” instead of relying entirely on raw pointer habits from C (If you couldn’t tell by now, I despise C). What changed The main work was split across lexer, parser, and typecheck. I added: ? as a type marker in type positions is_nullable tracking in TypeInfo type rules for nullable pointer/reference values explicit compatibility for: assigning null into nullable pointer-like types comparing nullable values against null casting between @T and ?@T I also kept the scope intentionally narrow: this implementation is pointer-first nullable support , not full nullable scalars. So ?@int makes sense right now, but ?int is still deferred until I make a better semantic union / optional representation for plain values. Why this matters It would have been easy to overreach here and claim “nullable types are done,” but that would have been a big phat lie. Pointer-like nullability lowers naturally enough with the current backend and current compiler model. Scalar nullability, however, does not. Once you let int or bool become nullable, you need a more real representation for “has value / no value,” and that belongs in the later union work, not here. Result explicit absence compiler-owned semantics better future unions stronger type meaning without hidden magic The next real step after this is not more patching around null — I consider that done for now — but instead giving Flower the deeper machinery needed for nullable non-pointer values and semantic unions later in v1.4 so it doesn’t come back to bite me in my butt.
v1.4.4 Devlog: Giving Flower Real Semantic Union Types I made it so that semantic unions are now in Flower’s parser and type system — but not yet its codegen. The goal was to support types like: value: int | string next: @Node | null type Result = int | string What’s new The parser now understands | inside type positions and builds semantic union type information instead of relying on those old plain aliases or backend-shaped hacks. On the typecheck side, unions are now carried through normal type copying and alias resolution. That means named aliases like: type MaybeName = string | null make sense after resolution, instead of collapsing into nonsense. The typechecker also now accepts union-compatible usage in the places that matter for a foundation: variable initialization assignment parameter passing return checking alias resolution So if a value matches one union member, it is accepted. This is sorta implicit behavior, but I think it gets a pass due to its somewhat explicit nature? What it does not do yet This version was intentionally strict about using unions as values. You cannot yet directly: index a semantic union access a field on a semantic union use arithmetic / comparison operators on one print one directly Instead, Flower now requires an explicit cast before using a union value that way. That may sound harsh, but it is the right restriction.. for now. There is not any narrowing yet, so pretending unions were fully usable would just make the language lie and spit out 2,000 errors. Where this leaves v1.4 Flower now has: transparent type aliases null as a real type-system concept pointer-first nullable types semantic union type representation The next step is the part that will make unions actually usable rather than merely legal: narrowing with is better explicit extraction with as eventually making ?T truly become T | null instead of remaining pointer-first for now No fun screenshot this time :p just frontend work for now… Ivy, signing off <3
Devlog: is Checks v1.4.5 added is checks, mostly so code like this can work: if maybe_ptr is @int: real_ptr: @int = maybe_ptr end The idea is (fairly) simple: if the condition proves maybe_ptr is an @int , the inside of the branch should be allowed to treat it like one. Flower did not know how to do that before. It knew what a variable was declared as, but it did not really learn anything from control flow yet. Now it can, at least for the pointer/nullable-ish cases I care about first. This touched the parser, AST, typechecker, narrowing logic, and codegen. So, naturally, the “small feature” went everywhere. I’d actually consider this one of the bigger refactors so far, mostly because it added a new TypeAtom structure. Before this, types were still a bit too attached to the places they appeared, and all fell under the TypeInfo . That worked for simpler declarations, but is checks needed type syntax to have something the compiler could pass around to use for comparisons, validations, and narrowing. The parser had to recognize the new expression shape. The AST had to store the left side and the tested type. The typechecker had to make sure the test was allowed and not totally garbage. Then the narrowing logic had to say, “inside this branch, this variable has the proven type of x and therefore we won’t flag you for being an idiot.” That last part was where the bug goblin lived. I’m calling them a goblin because they were sneaky (and I also think it’s quite a funny and cute name). For a while, Flower had applied narrowing from the if body instead of the if condition, which meant the compiler saw this: if maybe_ptr is @int: real_ptr: @int = maybe_ptr end and somehow still failed on the assignment inside the branch. Very helpful. Thank you, compiler. EVen though it’s obviously 100% my fault, I made the compiler, but oh well!! Once I changed the narrowing step to inspect the actual condition expression, it started behaving like it should. The typechecker could see maybe_ptr is @int , attach that narrowed type to the branch scope, and allow maybe_ptr to be used as @int inside the guarded block. For now this explicitness is how I want it. There may come a time in the near future where I decide some implicity is ok, but we’ll see ;) is checks are the first real step towards control-flow-aware typing in Flower. Not full union support yet, but definitely the beginning of that road soon to come. Right now it mostly helps with nullable and pointer-like cases. Later, the same idea can support richer unions, better narrowing, and more type-driven control flow without making the programmer manually restate everything the compiler should already know. Also, it bootstrapped cleanly twice — which.. is obviously the bare minimum, but still!!
Devlog: Semantic Unions Become Actual Values (Part I) In v1.4.6 , I made semantic unions actual runtime values instead of just parsed/typechecked shapes. Before this, Flower could understand: type Value = int | string as a type. It could point at it and say, “yes, that is a union,” but that was mostly theoretical. The goal was to make this work-work for realsies: type Value = int | string value: Value = 7 if value is int: n: int = value as int end value = "Ivy" if value is string: s: string = value as string end That meant Flower needed more than TypeInfo.is_union = true . It needed a full path from syntax, to type proof, to lowered storage, to runtime extraction. Otherwise unions would just be fancy typechecker thingy-ma-bobbies, which is not very useful when the backend still emits C. What changed Instead of treating a union as a vague “one of these types, probably,” Flower now lowers it into a tagged structure. Conceptually, this: type Value = int | string becomes something like: struct Value { int tag ; union { int as_int ; flower_string as_string ; } data ; }; Not the final sacred form forever, but that is the shape of it: a tag saying which variant is active, plus storage for the possible members. Since Flower emits C right now, the lowering is C-shaped. I am not fully sure how I want this to look in ASM yet, but I do know it would be way more technical, and uglier. This required a few things to play nicely with one another: if value is int creates a union proof the guarded branch stores narrowing information value as int is only allowed after proof assignments pack values into the right tagged member explicit casts extract the right member from storage Otherwise the compiler is just writing checks its own backend cannot cash. The part that makes it ACTUALLY semantic For pointer narrowing, if value is T mostly refines how the compiler treats an existing value. For semantic unions, the check also becomes a runtime tag test. So this: if value is int: means: check the active tag of value , then inside this branch, treat it as the int variant. Then this becomes valid: n: int = value as int because the branch already proved the active variant. Without that proof, value as int should not be casually allowed. Flower is supposed to be explicit, not psychic, and I am not confident enough yet to implement a proper intuitive implicit checker without summoning something cursed. Assignment and extraction This: value: Value = 7 now packs 7 into the int member and sets the tag to the int variant. Then this: value = "Ivy" does the same thing, but for the string member. So a semantic union is not just some bytes, but rather a tagged runtime object where Flower knows which member is active. Then explicit casts like: value as string can lower into extracting the string member, but only when the typechecker has accepted that the operation is safe in that control-flow path. Why this checkpoint matters Flower can now store variant values, prove which variant is active, and require explicit extraction instead of relying on random magic I threw together. The flower has grown another concerning little organ.
Devlog: Letting Semantic Unions Work In Functions After getting semantic unions working in local declarations, the next problem was fairly obvious (and in my roadmap hehe). This did not work before: func make_value(): int | string return 7 end func accept_value(value: int | string): bool return value is int end Which was annoying, because int | string was already a real union type at this point. Flower could use it in locals, it could pack assigned values, it could check variants. But if I returned 7 from a function declared as int | string , or passed 7 into a parameter expecting int | string , the compiler did not know how to carry that union-lowering information across the boundary. This has been one of the easier changes I’ve made in a long while. It compiled properly first try (if you ignore a tiny misspell I made which I fixed really quickly), and there were no prior hidden bugs that surfaced. This.. is too suspicious. What changed The compiler now carries semantic union info through: function parameters function returns imported alias calls If a function expects: int | string and I call: accept_value(7) typecheck records that 7 needs to be packed as the int member of that union. Same for returns: func make_value(): int | string return 7 end That matters because codegen cannot guess later due to the separation of responsibilities I’ve laid out. By the time Flower is emitting C, it needs to know which tag to set and which member to write. Lowering it properly Codegen already knew how to pack union values for declarations and assignments. The missing part was doing the same thing for call arguments and return statements. So now a value can be packed into a tagged union when it is: stored locally passed into a function returned from a function Alias calls got handled too, so things like: remote.accept(11) remote.make_string() do not become their own weird little cursed island. Why this mattered Without this, semantic unions only worked as long as I never organized my code. They worked in local tests, but not in helper functions, imported providers, or normal inputs and outputs. Now union values can actually move around the program instead of being trapped in the one scope where they were declared — and for me, forgotten! Very exciting, the union can leave the house. They grow up so fast ⁎⁍̴̛ ₃ ⁍̴̛⁎
Devlog: Adding Obvious Branch-Local Inference to Flower Before this, narrowing mostly worked in the obvious “true branch” cases: if maybe != null: real: @int = maybe end and: if value is string: s: string = value as string end But the else branch was still kind of standing there empty-headed, even when the meaning was extremely obvious. Like, if this happens: if maybe == null: return false else: real: @int = maybe end then inside the else , maybe is clearly not null. So now it doesn’t!! What changed Flower now does branch-local narrowing in else for small, explicit cases. That means these now work: if maybe == null: return false else: real: @int = maybe end and: if value is int: return false else: s: string = value as string end It is only applying inference when the condition says something directly and the opposite branch has one obvious meaning. Nullable narrowing For nullable pointer-like values, Flower now understands both sides of simple null checks: if x != null narrows x to non-null in the if body if x == null narrows x to non-null in the else body the opposite side can narrow to null when that is the only meaning left Semantic union narrowing The same idea applies to semantic unions, but a bit more ‘held back.’ Essentially, if Flower sees: if value is int: then the if branch narrows to int , like before. Now, if the union only has one other possible member, the else branch can narrow too. So for: int | string the else after if value is int can be treated as string . This is not full control-flow wizardry, since it doesn’t reason across deep boolean chains, early-returns, or giant branches yet. It is deliberately small and local, because I do not want Flower “helping” so much that I need a detective board to figure out what type something is.
Devlog: Teaching Flower to Understand Guard Clauses gave Flower branch-local inference. Last update, I added support for branch-local inference, so the compiler could understand things like: if maybe == null: return false else: real: @int = maybe end and: if value is int: return false else: s: string = value as string end That was an improvement, but it still meant narrowing stopped at the end of the branch. That meant stuff like returninging in some conditions still did not really work as naturally as it should: if maybe == null: return false end real: @int = maybe or: if value is string: return false end n: int = value as int In v1.4.9 I fixed that. What changed Now narrowing propagates past very obvious guard clauses. If one branch definitely returns and the other falls through, the compiler now carries the interpretation forward after the if . This means that the compiler can now understand: after if x == null: return ... , x is non-null after if x is string: return ... , a two-member semantic union can narrow to its remaining member I kept this intentionally conservative for now. The compiler is not doing full control-flow analysis yet. It is only recognizing the simplest and most explicit early-exit shape. How it works The main addition was a small semantic check for “does this branch definitely return?” Right now that means: direct return if where both branches definitely return Once the compiler knows one side exits and the other survives, it applies the branch’s narrowing to the following statements. Yea.. that’s it lol.
Devlog: Making ?T Actually Mean T | null Before v1.4.10 , ?T was treated as its own nullable system and not really integrated with the rest of the semantic unions. This was unideal, because it created a separation of logic which was cumbersome to maintain. The idea was to make the following be the default: ?int == int | null ?string == string | null ?@int == @int | null Prior to the refactor, nullable types were still mostly pointer-oriented. That worked when ?T basically meant “maybe this pointer is null,” but it did not really fit anymore once semantic unions became actual runtime values. If Flower has T | null , then ?T should use that instead of being its own special thing. This is a more pragmatic choice, as it keeps the compiler easier to manage and update later on. What changed Typecheck now lowers ?T into the same semantic-union machinery used by normal unions. That means nullable values now go through the same general path as union values: null checks use union-aware narrowing narrowed nullable values can be extracted with as codegen emits tagged union storage assignments pack into the right union member So this now works as an actual nullable flow: maybe: ?@int = raw if maybe == null: return false end real: @int = maybe as @int The annoying part is that Flower has to track two things at once: the type the programmer is allowed to see after narrowing, and the actual union shape that remains underneath it. After the guard, maybe behaves like an @int . But codegen still has to remember it came from @int | null , because apparently the compiler cannot simply “vibe” its way through storage layout. Tragic! The bugs that annoyed the heck out of me Most of the work was not surface syntax. The syntax was just standing nearby looking innocent. The actual bugs were in the places where Flower knew “this is non-null now,” but then forgot how to lower, such as: narrowed nullable values falling back to raw C casts like (int*)(maybe) false branches of == null / != null narrowing to the wrong side (this was my fault lol) null getting packed into the wrong union member That last one was the rude one. For ?@int , generated C could end up doing something like: . tag = 1 , . m0 = NULL instead of packing into the actual null member. So the value looked almost right, but the tag/member pairing was wrong. Then later null checks would fail, because the compiler had technically put null somewhere. Just not the correct somewhere. Very helpful. The fix was separating two questions I had accidentally merged: is this type compatible with this union? which exact union member should this value occupy? Those look related, but they are not the same question. Flower was using the first answer for the second problem, and then acting surprised when everything became soup. Where this leaves Better Types ?T now lowers through the same path as T | null , which means null checks, narrowing, extraction, and storage all line up with the semantic union model. This should make later work cleaner, such as nullable inference, nicer union ergonomics, maybe pattern-like narrowing eventually. Not easy. I am not saying easy near a compiler. That is how they hear you. You do not want them to hear you ..
Devlog: Direct Semantic Union Parameters Now instead of having to do this workaround: type Value = int | string func accept(value: Value): bool You can just pass semantic unions directly: func accept(value: int | string): bool That was it. All I had to do was remove a stale type_error clause in register_params and allow binding variables. Then I updated the two relevant accept functions in /examples.
Devlog: Letting Union Narrowing Follow Field Access Before v1.4.13 , union narrowing only really worked when the thing being narrowed had a variable name due to almost every similarity check relying on name_start and name_length . This was dumb, because semantic unions already knew how to test tags and extract members. Codegen was not the issue, but rather the annoying part was that the typechecker could remember this: if value is int: n: int = value as int end but not this: if box.value is int: n: int = box.value as int end So I still had to do a little temp-variable ritual: tmp: Value = box.value if tmp is int: n: int = tmp as int end Which was gross. Not necessarily catastrophic, just gross and annoying. I wanted needed convenience What changed The compiler was remembering narrowings by variable name, not by expression shape, so box.value looked obvious in source (to me, at least), but to the typechecker it was basically some random expression and not something it could reliably recognize again later. A variable name already had a stable identity, whereas field access chain did not. So the change was to let narrowable expressions represent more than just AST_VAR_REF . For now, that only means stable dot-access chains. The typechecker can record a narrowing for an expression like: box.value and then recognize the same expression later when a cast shows up. So this works directly now: if box.value is int: n: int = box.value as int end Same for the other union members, like string . The detour My first example accidentally wandered into a different feature: if maybe_box.value != null: That exposed a real nullable-field-guard gap, but that is not what this was supposed to be about. Very rude of the test case to have ambition hmph >:( Where this leaves it Semantic union narrowing now persists past field access — at least for stable dot-access chains — and the temp-local is no longer needed. Butttt now I gotta work on nullable-field-guards, ugh (hehe)
Devlog: Finishing Nullable Field Narrowing At this point, Flower could already narrow semantic unions through field access in the is / as case, and nullable field checks were supposed to be the obvious follow-through: if maybe_box.value != null: label: string = maybe_box.value as string end Instead, I had forgotten to remove a LOT of stale code, and thus part of it was still behaving like only plain local variables could ever be narrowed. There was also a second, smaller mismatch hiding, where null in type position was not lining up with the compiler’s actual internal null representation. ?string and string | null weren’t leading to a congruent output and at times were wobblier than they should be. So the fix was mostly cleanup, but the meaningful kind: make null in type syntax lower the same way the compiler expects remove the stale var-only branches in nullable narrowing let stable field paths like maybe_box.value and holder.box.value narrow properly The funny part is that this felt bigger initially than it actually was once fixed. Nothing fundamentally new had to be invented, I just had to stop the old code from interfering with the newer code, which once I figured out how to do so it was quite quick. I spent an embarrassingly long time figuring it out…
Devlog: Syncing Flower’s Docs Back to Reality Just a doc cleanup lol. No code change or compiler updates. Probably did more than needed for now but oh well! The mismatch was REALLY bad. The old docs preserve old assumptions, and someone reading them could walk away with a version of Flower that no longer really exists (or, in some cases, doesn’t exist yet or never ever existed)! What changed I updated the docs that had drifted the most from reality (relatable): README.md now reflects the current type-system shape ROADMAP.md treats v1.4 as accomplished the v1.4.0 milestone doc now includes more of the outcome, not just the original plan contributor docs no longer have stale semantics structure.md is more accurate to what Flower currently is, and what still needs a fuller rewrite later Yea, that’s it.
Devlog: v1.5.1 – v1.5.5 Following all of the changes Flower has undergone, I felt it was time for some much-needed documentation. On paper this was supposed to be fairly quick, simple, and not require much brain power. Unfortunately for me I got a bit too over-zealous, and included things I thought should work, but in reality hadn’t. For example, in a lot of the code snippets I’d have something like: for i in range 0..10: print(i) end Printing non-string values was not yet supported in Flower. To fix this, I took a small detour back to v1.4 and implemented support for it — mostly in a single codegen case: if ast.data._print.value_type.base == TOKEN_FLOAT or ast.data._print.value_type.base == TOKEN_DOUBLE: fprintf(out, "printf(\"%%f\", ") gen_expr(ast.data._print.value, out, src) fprintf(out, ");\n") end Afterwards I added more smoke-tests in examples/io/print.flo . Every few runs, however, I’d get a segfault. This was especially odd because it wasn’t simply an error but rather a silent memory bug. Eventually I found out where it was originating — thanks, ASan! Turns out after the new type system changes, I had forgotten to initialize some values to null / 0 in for loop handlers and a few other places. I just added typeInfo.data = null / 0 where applicable and it fixed the issue! What is v1.5, and why is this devlog so long? To answer the latter first.. I lowkey just forgot to post a devlog for the first two docs I made. That’s it. For the former question, v1.5 is supposed to be explicitly a documentation pass. First thing I worked on was structure. I cleaned up the docs layout, moved things toward a more consistent lowercase docs/ tree — I had been trying for so long to do that and I just finally got it to work — and wrote down the documentation process itself so new pages aren’t just floating about. The point was to try and make the docs feel like a book instead of a folder full of unrelated notes. I wrote and checked the language pages for types, functions, and control flow by reading the compiler itself, not by trusting my (poor) memory. That meant checking parser rules, typecheck behavior, codegen boundaries, and example files before writing anything solid. Types especially needed this, given how Flower now has enough real type machinery that the docs can quickly go from being coherent to completely incorrect: nullable sugar, semantic unions, explicit casts after narrowing, alias behavior, current member limits, and the difference between what the language wants to become and what the compiler supports currently. Functions and control flow had a similar issue. I had to document prop , return rules, direct call forms, logical conditions, range-based for , and the rough edges like break and continue not yet being enforced cleanly as loop-only. That kind of thing is small until someone learns the language from the docs and hits the edge head-first (been there, done that). What Now? I’m just going to keep writing docs. Maybe do one devlog for every new doc, or a batch of docs, who knows! I certainly don’t :p
Hey, it’s been a while! I’ve been finding it difficult to stay motivated for this project, especially with how the new payout system works and just my in-general inability to keep commitment despite having a lot of passion. That said, I am going back to working on this diligently, and I think to start I’m going to cut down on the documentation by making perhaps one or two changes, and then going right back to the compiler work. Documentation writing has not been the most fun for me, especially with how long it takes and how it’s so difficult to not only write language reference that works, but also keeping the same whimsy Flower should have. Thank you to everyone who’s been following this journey, and I can’t wait to see y’all later!!! With Love, - Ivy <3
Integer Types, Parser Fixes, and Segfaults! Phew — this one was biiiiiggg. Flower is pretty much just a glorified C transpiler, which is NOT what I want for it! In order to move on, the data has to be handled explicitly by the FloC. So essentially, I implemented i8 , u8 , i16 , u16 , i32 , u32 , i64 , and u64 . For now, int canonically refers to an i32 value. A New Era? With these new literals, the old hoist-sized representation had to go. The decimal source text is preserved, meaning values such as 18446744073709551615 remain after parsing without causing any overflow. Types are picked up from declarations, assignments, function arguments, return values, field writes, array-element writes, * breath in * and binary expressions! Oof, that was a mouthful. That, of course, resulted in proper errors for things like: 256 assigned to u8 −1 assigned to an unsigned type values beyond u64 unconstrained literals outside the default i32 range I Hate Memory During printing, every width is handled. Integer conditions retain existing zero / nonzero behavior, and literal types print their values rather than a character. Halfway through, I ran into sudden segfaults and memory leaks. I was taken aback, because I didn’t even change anything parser related yet. Turns out, I forgot an assignment in a declaration, which apparently the parser wasn’t able to handle (whoops!). Anyways, I fixed it by propagating errors through the compilation process, so the compiler doesn’t try to typecheck or code gen if the parser reports back errors, and instead will print them out. And that’s it! Not that’s it, but that’s all I’m going to explain for now. More specifics available on the GitHub, of course. Speaking of GitHub thank you so much to S1monr3dst0ne07 on GitHub for fixing some memory leaks in the previous version of Flower — I forgot to prune allocations before returning from a function :p Love y’all!! <3 P.S.: So glad I gave up on documentation, I was genuinely dreading workong on the project and that’s why I’ve been ianctive for a long time :c
Integers, Integers, Integers Hello!! Been a while :) Lately I have been working on v1.6. I call it the “Usefullness” update — rhymes with Grug — because it adds a ton of long awaited features and various convenience implementations Flower DESPERATELY needs. For example, currently the progress has to do with v1.6.1, or Fixed-Width Integers . When it comes to systems programming and in-general efficiency, having various integer sizes is important as it provides an additional layer of manual control over memory and sizes. I know I would have to add them eventualy, so why not put them at the start of the Usefulness update?? I’m sure they’ll come in handy later on. What Actually Changed? Well, for starters, there’s now fixed-width integers (yay)! They’re built in types, so you declare them as you would with any other atom / primitive: type Byte = u8 type Choice = Byte | u16 type OptionalByte = ?Byte struct Packet { pair: Byte[2], size: Choice, owner: OptionalByte } A whole bunch of commits and integer-specific changes regarding indices, arity, unions, nullables, etc etc etc have been made, and they all won’t fit here so instead, take a look at the current branch ! What’s In Store? Plenty more features, you can assure yourself! There’s maybe 6 or 7 — I swear — or so commits left for this specific addition, and after that a lot more features laid out in the roadmap for 1.6! As always, thanks for sticking around and watching the fiasco that is this project become more and more estranged with every hour. Love y’all!! Ivy <3
Ships:
Flower is a self-hosted programming language for writing simple, explicit systems code without the abstraction bloat and OOP-heavy direction a lot of modern languages have. The compiler is written in Flower itself, currently targets C, and follows a straightforward pipeline: lexing, parsing, module loading, typechecking, and code generation. Over the past few months, Flower grew from a small lexer/parser/codegen experiment in C into a way bigger language project than I couldv’e imagined. This wasn’t my first attempt at a language, but it has been my favorite! I implemented compiler-enforced module semantics, stronger type-aware codegen, real boolean support, real string support, and a small standard library foundation. Strings now have equality, .length, indexing, and explicit casts to and from @char , while modules support exported prop declarations, aliases as namespaces, and private-by-default top-level declarations. The hardest part was bootstrap stability. I ran into idempotency failures, parser edge cases, compiler corruption scares, and plenty of my own bad logic. A lot of the challenge was getting new features to work not just once, but consistently enough for the compiler to rebuild itself cleanly. One bootstrap it succeeds, and then the next I’m scrambling to figure out why the new binary executable has a corrupted parser despite just working (Still haven’t fixed that yet! It.. was really confusing and I’ve got no clue why it happened lol). I’m proud that I kept pushing through that and ended up with something much more fun to use than where I started — I mean, I don’t even have to write that much C anymore!! If people want to test Flower, the important thing to know is that it is self-hosted and still experimental, but it does work. The repo includes a bootstrap path, a test suite, and example programs covering types, control flow, memory, imports, strings, and bools. The current release is focused on making the core language feel real and usable before moving on to a larger standard library and a future non-C backend, so don’t be surprised if a C file is shoved in your face!
The compiler is written in Flower itself and currently targets C, so this release was mostly geared towards making the type system have actual Flower semantics instead of a thin little blanket over whatever the backend happened to be doing. The big additions in v1.4 were: transparent type aliases real null nullable types as ?T == T | null semantic unions like int | string explicit narrowing with is explicit extraction with as That support now works across locals, parameters, return types, struct fields, and stable field-expression chains. The work had to touch parser logic, typecheck, narrowing, lowering, codegen, bootstrap, and then all the weird regressions those changes politely dragged into the room. It was.. a process for sure What I’m most proud of is that v1.4 pushed Flower toward a clearer identity that wasn’t defined by C as much anymore. This release also brought the docs back in line with the compiler, which was LONGGGGG overdue. If you want to test it, the main things to look at are the Better Types examples and the self-hosting flow. The compiler should bootstrap cleanly, the test suite should pass, and the examples now cover aliases, nullable values, semantic unions, inference, and struct/field narrowing behavior. For those who will be testing it, DO NOTE that I develop exclusively on my MacBook which is a UNIX system! I do not have the ability to properly develop and provide releases for Linux-specificalities or non-POSIX systems. I’m extremely sorry for this, but alternatively watch the provided video to see Flower in action :) If you’re not able to test it, watch this short (crappy) video instead: https://youtube.com/shorts/DyPtIru6cjY?feature=share...
|
1792983049.3420923
|
1793069449.3420923
|
|
38774
|
Argo by @gismondi_simone | Stardance
|
gismondi_simone
|
0
|
104.12
|
0
|
[]
|
[{"post_id": 77676, "ts": "202 [{"post_id": 77676, "ts": "2026-10-07T20:20:35Z", "hours": 5.2086, "text": "The remote look so cool!!"}, {"post_id": 77166, "ts": "2026-10-05T21:16:00Z", "hours": 10.2169, "text": "It was a long 10 hours; I moved back and forth between different parts of the project. I installed the self-locking nuts onto the motor shafts (a very long, arduous, and boring process). Afterward, I built the entire conveyor system, but while i was working on it- and during a test run of the rover by my teammate-the brushless motor drivers burned out. We managed to get almost everything working in time to shoot the presentation video for the WRO. I assembled the entire scanner, mounted all the internal boards, and did a great job with the wiring. In meantime, I received a Centaury Carbon 2 Combo, a gift from our sponsor, Crea 3D."}, {"post_id": 75388, "ts": "2026-09-29T22:10:35Z", "hours": 5.8122, "text": "it’s been a tough few hours, I’ve build a tensiometer for the rover’s wheels, assembled the scanner module, and concluded the initial motion test."}, {"post_id": 72798, "ts": "2026-09-23T19:12:08Z", "hours": 0.8822, "text": "I’ve done some adjustment to reinforce the 3d printed motor parts"}, {"post_id": 72411, "ts": "2026-09-22T21:18:14Z", "hours": 0.9353, "text": "I’ve cleared up some of my doubts about the motion of the rover, though I’m far from having solved all of them"}, {"post_id": 71225, "ts": "2026-09-20T14:09:49Z", "hours": 2.4167, "text": "The motor is working!!!! I’ve done some important circuit for the power management of the rover battery."}, {"post_id": 69689, "ts": "2026-09-17T16:09:34Z", "hours": 1.6169, "text": "I’ve fixed some issue due to a wrong manufacturing processes."}, {"post_id": 67476, "ts": "2026-09-13T16:22:23Z", "hours": 4.8061, "text": "Finally I’m working on the thing"}, {"post_id": 64230, "ts": "2026-09-08T14:15:25Z", "hours": 3.8139, "text": "I’ve checked all the screws and bolts, for the BOM, though I found some mistakes due to the last minute changes that I made yesterday. Unfortunately I’ve already committed the laser cutter job :("}, {"post_id": 64089, "ts": "2026-09-08T08:21:15Z", "hours": 1.85, "text": "I’ve done the v.3 of the nesting file to match the wood sheets that I found in my local hardware shop"}, {"post_id": 62919, "ts": "2026-09-06T13:40:57Z", "hours": 3.8875, "text": "I’ve added the linear motor to the conveyor, I’ve also modified the nesting and the printable files to match the modification"}, {"post_id": 60961, "ts": "2026-09-03T17:19:20Z", "hours": 5.1003, "text": "I’ve organized all the printed parts on 15 different plates :) I’ve also done minor changes on the conveyor."}, {"post_id": 60305, "ts": "2026-09-02T16:11:59Z", "hours": 5.7003, "text": "I’m working on the nesting layout file. I’m gonna send it to my local fablab as soon as possible. I’ve also fixed some problems. Next steps are: 1)Create the 3d printing layout for every pieces, 2)Make a list of all the screws and bolts that I need (A LOT), 3) Buy everything and assemble it."}, {"post_id": 57965, "ts": "2026-08-30T09:30:34Z", "hours": 5.9336, "text": "The scanner module is almost ready for production"}, {"post_id": 55670, "ts": "2026-08-27T17:07:51Z", "hours": 6.0717, "text": "I’ve made a lot of adjustments to the parts that carry Argo’s load. I’ve also started working on the scanner module."}, {"post_id": 41218, "ts": "2026-08-05T09:31:20Z", "hours": 7.2153, "text": "The structure of the Rover is ready!! Next steps are: Adding a linear actuator at the end of the conveyor belt The scanning area The remote PCB’s"}, {"post_id": 39606, "ts": "2026-08-02T18:15:17Z", "hours": 3.4086, "text": "The majority of the conveyor is DONE!!"}, {"post_id": 38910, "ts": "2026-08-01T14:31:50Z", "hours": 9.4842, "text": "Few parts missing!!"}, {"post_id": 37708, "ts": "2026-07-30T16:45:18Z", "hours": 4.4339, "text": "Kinda there"}, {"post_id": 37161, "ts": "2026-07-29T17:37:19Z", "hours": 4.3397, "text": "Still working on the conveyor"}, {"post_id": 36512, "ts": "2026-07-28T17:49:31Z", "hours": 1.7336, "text": "I’m finally starting to see the light at the end of the tunnel."}, {"post_id": 35932, "ts": "2026-07-27T18:08:55Z", "hours": 5.3317, "text": "I HATE SolidWorks :("}, {"post_id": 34154, "ts": "2026-07-24T17:38:23Z", "hours": 1.6, "text": "Just a HUGE pillar!"}, {"post_id": 34031, "ts": "2026-07-24T13:33:19Z", "hours": 2.3169, "text": "I’m working on Argo with @Pollo"}]...
|
Title: Argo by @gismondi_simone | Stardance
Devlo Title: Argo by @gismondi_simone | Stardance
Devlogs:
I’m working on Argo with @Pollo
Just a HUGE pillar!
I HATE SolidWorks :(
I’m finally starting to see the light at the end of the tunnel.
Still working on the conveyor
Kinda there
Few parts missing!!
The majority of the conveyor is DONE!!
The structure of the Rover is ready!! Next steps are: Adding a linear actuator at the end of the conveyor belt The scanning area The remote PCB’s
I’ve made a lot of adjustments to the parts that carry Argo’s load. I’ve also started working on the scanner module.
The scanner module is almost ready for production
I’m working on the nesting layout file. I’m gonna send it to my local fablab as soon as possible. I’ve also fixed some problems. Next steps are: 1)Create the 3d printing layout for every pieces, 2)Make a list of all the screws and bolts that I need (A LOT), 3) Buy everything and assemble it.
I’ve organized all the printed parts on 15 different plates :) I’ve also done minor changes on the conveyor.
I’ve added the linear motor to the conveyor, I’ve also modified the nesting and the printable files to match the modification
I’ve done the v.3 of the nesting file to match the wood sheets that I found in my local hardware shop
I’ve checked all the screws and bolts, for the BOM, though I found some mistakes due to the last minute changes that I made yesterday. Unfortunately I’ve already committed the laser cutter job :(
Finally I’m working on the thing
I’ve fixed some issue due to a wrong manufacturing processes.
The motor is working!!!! I’ve done some important circuit for the power management of the rover battery.
I’ve cleared up some of my doubts about the motion of the rover, though I’m far from having solved all of them
I’ve done some adjustment to reinforce the 3d printed motor parts
it’s been a tough few hours, I’ve build a tensiometer for the rover’s wheels, assembled the scanner module, and concluded the initial motion test.
It was a long 10 hours; I moved back and forth between different parts of the project. I installed the self-locking nuts onto the motor shafts (a very long, arduous, and boring process). Afterward, I built the entire conveyor system, but while i was working on it- and during a test run of the rover by my teammate-the brushless motor drivers burned out. We managed to get almost everything working in time to shoot the presentation video for the WRO. I assembled the entire scanner, mounted all the internal boards, and did a great job with the wiring. In meantime, I received a Centaury Carbon 2 Combo, a gift from our sponsor, Crea 3D.
The remote look so cool!!...
|
1792752860.1323378
|
1793357660.1323378
|
|
927
|
Squirrel by @Koei | Stardance
|
Koei
|
3
|
104.0
|
1915
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-19T13:34:37Z", "hours": 29.0, "multiplier": 17.36, "payout": 598, "blessing": "neutral", "text": "v1.0.0 Squirrel is a clipboard manager for Windows and X11 Linux that is meant to be simple and intuitive. This major release overhauls the data storage schema to be more efficient, faster, and reliable. There are significant performance improvements. This release also adds configurability to Squirrel, allowing basic but much needed customization, and polishes up the overall app. Check the README for more information.", "repo": "https://github.com/Koei32/squirrel", "demo": "https://github.com/Koei32/squirrel/releases/latest"}, {"ship_num": 2, "ts": "2026-07-26T14:30:06Z", "hours": 30.0, "multiplier": 13.88, "payout": 499, "blessing": "neutral", "text": "v0.3.0 Squirrel is a clipboard manager that is meant to be simple and intuitive. 2 new features in this version, namely pinning and image support. There are performance improvements as well as slight visual tweaks. Read the README for more info.", "repo": "https://github.com/Koei32/squirrel", "demo": "https://github.com/Koei32/squirrel/releases/latest"}, {"ship_num": 3, "ts": "2026-06-23T16:48:48Z", "hours": 45.0, "multiplier": 18.23, "payout": 818, "blessing": "neutral", "text": "v0.1.0 Squirrel is a clipboard manager that is meant to be simple and intuitive. It remembers all the text you copy allowing you to paste whatever into wherever. You can also quickly search through your history. Squirrel is meant to be cross-platform, but for this release, Linux support on Wayland is very iffy (X11 is fine for the most part). I would highly recommend using Windows for testing this ship, sorry for the inconvenience. Expect potentially better support next ship.", "repo": "https://github.com/Koei32/squirrel", "demo": "https://github.com/Koei32/squirrel/releases/latest"}]...
|
[{"post_id": 63114, "ts": "202 [{"post_id": 63114, "ts": "2026-09-06T18:50:53Z", "hours": 4.0806, "text": "v1.0.0 It’s official. Squirrel is now v1. devlog time is adding logging, updating readme, fixing some small tidbits and polishing up some areas of the app. Squirrel now prints pretty logs to console when running in development mode and writes logs to a file if running in release. Project status i realistically can not get a GUI settings panel done due to me needing to divert my attention to more important life stuff. this right here is probably going to be the extent of work done on Squirrel in stardance. i definitely do plan on working on this in the long term. for example, im not entirely happy and satisfied with the current UI, and global hotkey still does not work on wayland. but right now, more pressing issues are at hand and i cannot give it my all on this project. that said, i do believe that Squirrel is in a very usable 1.0 state, which was my goal. i might push minor updates if the reviews call for fixes/improvements, but definitely no major features. thanks for reading if you made it here."}, {"post_id": 54719, "ts": "2026-08-25T19:56:34Z", "hours": 3.9647, "text": "History persistence configuration now works. setting it to false means history is not retained between sessions. comes with true as default. pinned entries always persist. attachment shows the behavior when persistence is off. Implementation i ended up deciding not to do the in memory database method for this since it was a bit too much added complexity which could be avoided by just adding an additional is_persistent column to the db. im not the happiest about how i’ve implemented this right now but im willing to take that hit right now if it means i dont have to deal with databases. Next all of the config options are now implemented. we are very close to v1.0. expect progress to be rather slow from here on out. i’ve had to divert my attention towards other things and haven’t been able to spend a lot of time working on my projects. maybe i will work on a settings panel. depends on how much work it requires. it’s a maybe. i may just ship it as it stands right now."}, {"post_id": 51853, "ts": "2026-08-21T18:35:09Z", "hours": 0.8633, "text": "Item expiry and pin-preservation expired items are now automatically deleted on program startup. an entry is considered expired when the current time is more than its expires_at value. when pinned, the expires_at attribute is nulled, meaning this entry will never expire. the “Clear all” shortcut Ctrl+Shift+Del now respects pinned entries. it clears everything but leaves pinned entries untouched. Next the ephemeral db shenanigans. also, i have decided that Squirrel needs a settings panel in the frontend for easier config modification. that may or may not happen but it is tempting to do it."}, {"post_id": 51243, "ts": "2026-08-20T19:36:27Z", "hours": 5.9658, "text": "(i genuinely have no idea what to show in the devlog attachment, nothing’s changed visually. so have this stupid ass screenshot.) Massive refactor, breaking changes now that i’ve given myself the liberty to rethink and redesign Squirrel’s data models and storage in a breaking fashion for v1, we have managed to make a good amount of improvements across the board. database schema has been modified to better suit current needs and make it possible to implement the features I desire for v1. it has been a very satisfying refactor. What’s new: use UNIX microsecond timestamp for event ids instead of relying on sqlite autoincrement. this allows us to immediately send a captured event to the frontend without having to await a db write to obtain the event id. this also eliminates the timestamp column for events since the id is also the timestamp. a dedicated BLOB column for image entries to store raw image bytes instead of b64 encoded strings. this makes images weigh about ~33% lighter. decent perf boost. new expires_at column to store when an entry expires. pinned entries have an expiry of NULL . provides the base to actually implement expiring entries. get rid of ClipboardEventNotice since we no longer do the notify frontend -> write to db -> send data to frontend dance. it is now simply send whole event to frontend -> write to db . we enjoy simplifications. (!) as it stands now, old data (if it exists) would immediately be wiped when launching Squirrel v1. i could write some migration code but we’ll see. maybe clipboard data isn’t important enough to bother with migration. Next: actually implement entry expiration: should be trivial, just delete expired entries on launch. ephemeral/persistent toggle: this one is a bit tricky, and will involve some in memory database shenanigans. more details in the devlog when i implement this."}, {"post_id": 47102, "ts": "2026-08-14T19:04:13Z", "hours": 0.8614, "text": "Ignore programs you can specify programs in which Squirrel should not listen to clipboard events. this is useful when you’re working in a program wherein you need to use copy and paste a bunch. ignoring that program would keep your Squirrel history clean. also useful to ignore a program that you regularly copy secrets from. example of notepad being ignored:"}, {"post_id": 46488, "ts": "2026-08-13T18:43:57Z", "hours": 3.6642, "text": "devlog attachment obligation: here is me pasting some files i copied a couple minutes ago after i copied stuff on top of that. that out of the way, devlog. Several things app theme is now configurable from config, so you are not stuck with the system theme if you want to change it. cleanup across the backend; comments, TODOs, error handling, and stuff of the sort. performance enhancement in the clipboard event emitter loop. bugfix in the same loop where the thread panicked if you copied something while the app was launching. merged the config branch. the remaining config options would be better to implement in their own branches. dependabot updates"}, {"post_id": 46172, "ts": "2026-08-13T06:19:26Z", "hours": 3.2672, "text": "Configuration (wip) Squirrel now has a configuration file. squirrel.toml is created in the config directory of your OS (i.e. %appdata%/Squirrel on windows and /home/username/.config/Squirrel on linux), finally allowing some amount of customization support. right now, only the types and the max_image_size config options work. types allows you to choose which kind of clipboard items are captured/ignored. max_image_size is self explanatory. attached is the full config file. the remaining options require a bit of work to implement."}, {"post_id": 44184, "ts": "2026-08-09T19:34:47Z", "hours": 0.5053, "text": "Turns out, copy and paste support for files was a one line diff. also, Squirrel is now v0.4.0, yippee. anyways, moving swiftly on. Planning for a v1.0 Squirrel is now in a state where we have most of the major features i wanted it to have: support for essential clipboard data types, pinning and search. however, it is not quite in a v1.0 state. there are a bunch of things i want to add to polish up the program and make it feel sort of “complete”, which is mainly focusing on some basic configuration ability. since sensible defaults are hard to figure out, i’d rather let the user break things instead of being stuck with my arbitrary decisions. thus, i present the current planned feature list for v1: Configuration : enabling basic behavior customization through a config file (TOML most likely) Program exceptions : dont capture clipboard data on certain programs Auto delete/never store : ability to specify a “shelf life” for items, or whether to store them persistently at all. Disable specific types : ability to pick which kind of clipboard events to capture, i.e. only text or text and images, etc. Configurable image size threshold : currently locked to 5mb, this would allow to specify a custom value. (?) Custom data storage format : still torn on this, but there may be performance to be gained by moving to a data store more geared for our purposes. this list ofcourse, might change. implementing these features would make Squirrel much more flexible, and make it v1 worthy."}, {"post_id": 43522, "ts": "2026-08-08T20:50:19Z", "hours": 5.0344, "text": "Rudimentary file support we now have the most basic kind of file support there could be. which is just storing the path to the file. we then provide a link to the file in the frontend, clicking on which reveals the file in your explorer. we also now have tiny little icons on the entries which indicate the entry type. all icons thanks to https://lucide.dev/ files ofcourse, need a bit more work. right now, you cant really do much except revealing in explorer. i will work on adding copy and paste support for files next, as well as maybe improve the overall performance a bit."}, {"post_id": 40907, "ts": "2026-08-04T18:49:27Z", "hours": 0.4922, "text": "Acting on feedback a shipwright recommended i change my banner to include a screenshot of the program. so we now have a shiny new banner that should look good everywhere on the site. this required me to figure out what dimensions the banner is shown at across the site. i’ve attached a rough template for banners. fitting everything inside the marked areas should make sure your banner isn’t cut off anywhere that matters. one reviewer rightfully couldn’t figure out how to quick paste items. this is a miss on my part because i didn’t really have a list of shortcuts anywhere and kind of just mentioned them in passing in the README. that has been rectified by adding a Shortcuts section to the readme."}, {"post_id": 35201, "ts": "2026-07-26T13:57:06Z", "hours": 0.8461, "text": "Set for ship release is made, README updated. should be good to go."}, {"post_id": 33659, "ts": "2026-07-23T19:06:47Z", "hours": 0.9039, "text": "Basic image cache we now cache the last 32 images, fetching from the backend when required and updating the cache. made the image re-rendering issue instantly better. attached is the demo video i forgot to upload in the second to last devlog showing images in action. Performance images are a difficult thing to handle, especially when dealing with the system clipboard. i’ve made Squirrel as performant as i could to the best of my abilities, which is to say, it’s not the best. it isn’t as rich as i would like it to be, so i might return to this feature to improve it in the future. one restriction i’ve put on images to control some of the chaos is limiting the size to 5 megabytes, meaning any image above 5 megs isn’t registered. i could push that to 10, which is still practically instant. but Squirrel is intended to be a quick clipboard, and not dropbox. so this is my cheaty little escape. maybe i’ll relax the limit in the future if 5mb is really restrictive. Next? i’ll probably bump the minor version and ship (i wouldn’t dare a v1.0 currently). i’d say pinning and image support is enough to warrant a second ship. beyond that though, stands file(s) support, so a lot of decision making on how i want it to work to have a good balance of performance and usefulness. a bit of a lengthy devlog this one, and i appreciate if you read all that. but i wanted to clear up some things for myself and just have a frame of reference where Squirrel stands right now after returning from a development break."}, {"post_id": 33376, "ts": "2026-07-23T08:11:18Z", "hours": 0.3458, "text": "Image branch is merged yay, yippee even. next i need to implement a frontend cache to store the last X entries’ contents, particularly for images. the way it works right now, every time the images are re-rendered (due to being filtered by search, for example), content is fetched from the backend. this ofcourse, is less than ideal. but shouldnt be a lot of trouble to fix."}, {"post_id": 32539, "ts": "2026-07-21T19:47:15Z", "hours": 4.9058, "text": "Bunch of things Image Improvements some performance enhancements with images. made the clipboard image data fetching happen in Tauri’s dedicated thread pool, effectively parallelizing the operation. this made image copying a lot faster. image support should be merged into master soon enough. Lazy loading we now have lazy loading for images. image data isn’t loaded until it is scrolled into view. makes startup quick. CI enabled Dependabot updates and optimized the lint workflows for PRs. previously, all of the project was lint+checked on PR when changing anything. now it only checks the part that’s changed (i.e. frontend or backend)"}, {"post_id": 31397, "ts": "2026-07-19T18:47:59Z", "hours": 4.4964, "text": "Progress on images we finally have some form of working image support in Squirrel. This required even more sweeping refactoring changes to the codebase, which was a bit painful and im sure the new code isn’t the best quality either and will bite me later, but we’ll deal with it when we deal with it. getting images is a bit slow however, as right now we’re storing the image as base64 encoded PNGs. i plan to use the SQLite blob type to just store the raw bytes and pass that back and forth to improve the performance a bit (maybe some sort of caching as well?). there are also other areas where that are to be improved but i wanted to get a somewhat working prototype as fast as i can. explaining the silence i’ve been distracted by some life stuff, making me neglect my projects a bit. i also got distracted by the ESP32, fun little device. that is where the 9 days went. but, expect me to work semi-regularly again. thanks for reading."}, {"post_id": 26042, "ts": "2026-07-10T16:57:23Z", "hours": 3.0411, "text": "Lots of refactoring (apologies for the uneventful devlog attachment, i have nothing interesting to show except just code) to make it a bit more manageable when adding image support, a bunch of refactoring and reorganizing has been done in the backend. like i’ve previously mentioned, the codebase leaned too hard into only supporting text events. this fixes that. today’s changes also make the internal communication a bit more efficient. there are a couple more places where performance can be improved. and we will need every bit of performance we can get when dealing with image data. Changelog (shoutout @Hridya for stardance utils, just discovered this) 5b3f285 refactor: move clipboard structures into separate file b3ab1c8 perf: only get required data from db when copying an item 69dc003 refactor: modify data types to enable addition of image support Release CI (wip) currently writing the Release workflow for Squirrel. i have to figure out how to upload the artifacts to a github release with proper versioning and all that. the strategy is to run the workflow whenever something is pushed to the release branch. that is all for today."}, {"post_id": 25496, "ts": "2026-07-09T20:07:22Z", "hours": 0.7936, "text": "Version bump and docs bumped the minor version. Squirrel is officially v0.2.0, yippi. plus, updated the README, adding more explanation about the Wayland issue. also showcased the pin feature. i’ll try to whip up a release workflow to add to my CI tomorrow. I’m debating whether i should ship v0.2.0. the only major change from 0.1.0 is the addition of pinning. i might wait until i have image support and ship later, or i might change my mind, im unsure."}, {"post_id": 24896, "ts": "2026-07-08T19:03:24Z", "hours": 1.2706, "text": "Closed 1 (one) issue moved the global launch hotkey logic from the frontend to the backend. it didn’t behave well in certain situations, failing to activate and bringing up the Squirrel window. Starting work on images we’re experimenting with images. the current functionality is very much caveman and needs a lot of attention to make it actually usable. i’ve decided to stick with clipboard_rs for now, we’ll see how that pans out."}, {"post_id": 24277, "ts": "2026-07-07T18:55:23Z", "hours": 4.1067, "text": "Sadness so i just found out that Tauri’s global shortcut plugin does not yet support Wayland, which is sad to discover this deep into development. but, there is an active PR addressing this issue , which is nice. what this means for Squirrel is that proper Wayland support will unfortunately have to wait until this is merged. the joys of using a not-yet-completely-matured framework i suppose. though it does make me feel a bit guilty for calling Squirrel “cross-platform”. in other news (changelog): Squirrel now has a --silent launch flag that makes it start with the window hidden. useful when the app is set to launch on system startup. Squirrel now makes sure there is only one instance of it running. The shortcut Ctrl+Shift+Del will clear history permanently. (i forgot about clear history functionality in the first ship even though the code for it existed, there just wasnt a button in the frontend to call it)"}, {"post_id": 22186, "ts": "2026-07-04T14:50:25Z", "hours": 4.1014, "text": "CI dipped my toes into github workflows, messed around, an got check&lint workflows working on pull requests. will make a release workflow some time later. this change however, was only a part of this devlog’s time. Bad decisions catching up turns out, using clipboard_rs might’ve been the subpar choice for interfacing with the system clipboard. while clipboard_rs provides a easy way to listen to clipboard changes and get text from it, fetching raw clipboard data is buggy and inconvenient. when i sat down to work on image support, i was immediately brick-walled by how messy it is to just get raw data first. it would’ve been simple if i was building for just one target os but considering both windows and linux, it’s less than ideal. on top of this, the documentation for the crate is very lackluster. all this to say, i am very much debating migrating my clipboard stuff to using arboard . arboard doesnt provide direct functionality to listen to clipboard changes so i will have to implement that myself. but, it does have first class support for wayland. a very enticing choice, but we will see."}, {"post_id": 18315, "ts": "2026-06-29T12:51:11Z", "hours": 2.7625, "text": "Navigation improvements slight refactoring and bugfixes for frontend navigation. the navigation was kinda wonky before this and sometimes wouldn’t highlight the entry that was actually selected in the background. most of this devlog’s work was to make it so that what you see is what you get. also, a touch of color has been added to pinned entries (tentative)."}, {"post_id": 17064, "ts": "2026-06-27T18:22:53Z", "hours": 2.5814, "text": "Pins we now have basic entry pinning support. this was a bit less difficult than i thought it was going to be. but now you can pin an item and it always stays at the top of the list (unless you’re searching). anyways, that is one item ticked off the todo list. apart from that, i had to do some minor backend refactoring and reorganizing so that it is easier to build more upon. next? image and/or file copy support. this is one monumental task. i think the way we’ll approach this is by storing the entire file if it’s smaller than, say 5mb, and if it is larger, we just store the path to the file. we dont want to store the user’s 5gb video file they just copied. for images, i think the play is to generate a low quality thumbnail of the image to display in the app. for files, if it is a text file, we can show just the first 5 or so lines with a link to the file, other wise we’ll just give a link. until now, the code i’ve written sadly relies too much on the fact that every event is a text copy as we ignore everything else. it’s going to be a rather painstaking experience refactoring the codebase. the challenge is going to be keeping Squirrel quick and responsive while supporting all of this additional functionality."}, {"post_id": 14387, "ts": "2026-06-23T14:34:01Z", "hours": 2.1467, "text": "even more bugfixes ofcourse critical bugs pop up when im trying to release. the system tray icon wouldnt show up when running the single-file executable on any platform. that is now fixed. plus a couple more things have been done to make Squirrel behave like a good cross platform app, like storing the data in the OS’s appdata directory. there are some more things i would like to do but i think the app is in a releasable state and i’ve wanted to ship it for a while. I’ve set up the GitHub release and all the relevant instructions in the README. might be last devlog before ship #1."}, {"post_id": 11396, "ts": "2026-06-18T17:34:03Z", "hours": 1.2267, "text": "more polish and minor fixes more readme refining, linux support clarity, and installation instructions. also, i completely forgot about the tray icon actually needing an image icon, so until now it was just blank. anyways, we now have an icon. next, we put out releases on github and ship, hopefully. unfortunately we have to wait until tomorrow for linux builds."}, {"post_id": 10100, "ts": "2026-06-16T18:11:51Z", "hours": 1.3953, "text": "readme and polishing preparing to ship, writing docs, recording demos and stuff. there are a couple other things i want to sort out but i might ship in a few days."}, {"post_id": 9339, "ts": "2026-06-15T17:46:59Z", "hours": 2.4394, "text": "Dark theme! just glorious there isn’t a theme toggle button yet, it just goes off of your system’s theme for now. now that the colors are roughly standardized across the ui, tweaking the contrast and palette is a much more pleasant experience."}, {"post_id": 8830, "ts": "2026-06-14T18:02:58Z", "hours": 0.6531, "text": "wip dark theme support i want squirrel to use whatever theme the system is set to. currently it’s forced light mode but dark mode is something i’d be crucified for not adding. unfortunately, I in my infinite wisdom didn’t have the foresight to have consistent colors across even the light theme itself. there’s just random #aaa , #666 , etc colors everywhere where i went with what looked good. so work needs to be done to standardize the colors with css variables. then just modify the variables for dark theme accordingly. yes, i’m aware this is standard practice."}, {"post_id": 8047, "ts": "2026-06-13T12:50:39Z", "hours": 1.6972, "text": "Ticked a couple of items off the todo list: Squirrel now loads the history on launch. doing this was easier than i expected, but it’s a very naive way to do it (literally just send all of the history on launch). we also now have a logo. im no graphic designer by any means so this is the best i could do. shows in the titlebar and when your history is empty. check the project banner for a larger version if you feel like it. i might change the logo in the future, i just wanted an icon. todo pinning items test on linux"}, {"post_id": 7571, "ts": "2026-06-12T17:36:06Z", "hours": 1.2175, "text": "nothing significant. just docs and comments and cleanup. slowly making progress planning wise into loading the history at launch. the idea is to use a custom Tauri IPC Channel for incrementally streaming data to the frontend on app start. channels are supposedly faster for this and are meant for continuous messages like this in comparison to events. from the Tauri docs: Channels are designed to be fast and deliver ordered data. They are used internally for streaming operations such as download progress, child process output and WebSocket messages. i may implement a lazy loading system if i feel like it. i have nothing interesting to show so have a squirrel again"}, {"post_id": 6978, "ts": "2026-06-11T18:27:06Z", "hours": 4.3067, "text": "Item search i’ve wanted to add this for a long time but it needed a lot of refactoring in the frontend so i put it off for later. it is now later. we have instant search. press / or any of the non shortcut keys to start searching. frontend logic has had a big refactor making navigation and other operations more predictable and less wonky. it took a bit of battling with the specifics of Svelte’s each loop and bind:this directive but it was worth it. there is still some cleanup that can be done, the code is not idiomatic by a long shot, but im happy we have a very essential feature complete. changelog: add search fix broken arrow navigation and copy/delete operations applying to wrong entries. make window size a bit bigger by default (might change later) make copy icon turn into a green checkmark so that there is some visual feedback on copying make the database file always save at the executable’s location. todo ! still need to test linux ! load history on launch app icon and branding"}, {"post_id": 6358, "ts": "2026-06-10T18:17:34Z", "hours": 5.3111, "text": "Frontend improvements we now have buttons on the clipboard entries so you can also use the mouse to perform the basic functions like copy, delete, etc. (pins wip). there have also been a bunch of UI improvements and tweaks in general. deleting feels instant. navigation is fixed (for the most part). Backend slight optimization in the pasting operation, plus a couple of fixes and doc comments."}, {"post_id": 5833, "ts": "2026-06-09T19:30:37Z", "hours": 0.4139, "text": "custom scroll bar that is it, enjoy."}, {"post_id": 5013, "ts": "2026-06-08T17:39:05Z", "hours": 2.1789, "text": "UI tweaks as i mentioned before, im in the process of simplifying the UI. i hid the native titlebar and made a custom one. also tweaked the shape of the window to feel more like a clipboard. that is all that’s changed significantly this devlog. development will probably slow down a little bit in the coming days because i have irl stuff to deal with."}, {"post_id": 4379, "ts": "2026-06-07T18:13:01Z", "hours": 4.3942, "text": "more backend there isnt any significant change in the frontend but there’s a ton of backend refactoring and bugfixes. performance should be slightly better now with large copy/pastes. changelog: associate IDs with clipboard events so that we only have to pass IDs between the frontend and backend instead of the whole content. make paste operation more efficient ignore clipboard events caused by Squirrel itself (a bit hacky to achieve this but good enough) Quit button in tray icon menu so Squirrel can actually be closed (there was no way to close it before except killing it) make the shortcut to bring up Squirrel work in almost all situations refactor AppState + some other things more cleanup and comments anyways, attached image is the tentative color palette i might implement. i have no idea how to do this and which colors to use where or if it would even look good so i might just ditch it in the future. we’ll see. todo still have to test on linux and load history on app launch. probably will work on that next."}, {"post_id": 3711, "ts": "2026-06-06T19:20:52Z", "hours": 3.0414, "text": "we got shortcuts we now have Ctrl+Shift+V as the shortcut to bring up Squirrel. (i know it’s used for “Paste as plain text” in some programs and used for “Paste in place” in photoshop but whatever). once up, you can select items from your history using arrow keys. pressing Return pastes the selected item into your last window. we’re having some issues with permissions but i’ll look into it. i’m now slowly simplifying the UI to be geared more towards improving user ergonomics and make it something that is not cluttered and easy to use. apart from this, i’ve cleaned up the code a bit removing stray debug prints and random commented code, it was getting out of hand. will write proper doc comments soon. todo i have to make the app load the user’s past clipboard history on startup lmao i totally forgot i have to start testing on linux, urgently. i feel i should make devlogs more often. even if nothing’s changed in the actual project, detailing plans helps me keep track of things personally. that’s pretty much it, stay tuned. edit: please ignore the VC_UNDEFINED keys in the input overlay in the attached video, it’s Enigo inputs not translating well."}, {"post_id": 2305, "ts": "2026-06-04T18:30:06Z", "hours": 4.1042, "text": "a bunch of backend improvements: store timestamps for copy events more efficient message passing between frontend and backend Clear History functionality system tray (!) (pls ignore the missing icon in the tray, we don’t have an icon for the app yet) slightly better UI on the topic of UI, i’m getting around to deciding a color palette for the app. i will probably work more on the UI for a bit before switching gears to add more functionality (like image support). if i decide i want to ship early, v0.1 will probably go without image support and just get a lot of polish with text only functionality."}, {"post_id": 1590, "ts": "2026-06-03T18:26:51Z", "hours": 3.9078, "text": "frontend improvements! spent some time battling css for this relatively simple UI but it’s atleast somewhat pleasant to look at. will work on either image support or making it the app run in the background next."}, {"post_id": 922, "ts": "2026-06-02T17:41:08Z", "hours": 4.1017, "text": "nothing much has changed visually, but we now have a database to store the user’s clipboard actions. plus some refactoring changes and a bunch of minor improvements here and there. i have nothing to show for it except code so instead have an image of a squirrel"}, {"post_id": 261, "ts": "2026-06-01T13:38:29Z", "hours": 2.5611, "text": "init. figuring out Tauri’s emit/invoke mechanism and capturing clipboard copy events. slow start. we’ll do the color palette and icon and all the frontend pleasantries at a later date."}]...
|
Title: Squirrel by @Koei | Stardance
Devlogs:
ini Title: Squirrel by @Koei | Stardance
Devlogs:
init. figuring out Tauri’s emit/invoke mechanism and capturing clipboard copy events. slow start. we’ll do the color palette and icon and all the frontend pleasantries at a later date.
nothing much has changed visually, but we now have a database to store the user’s clipboard actions. plus some refactoring changes and a bunch of minor improvements here and there. i have nothing to show for it except code so instead have an image of a squirrel
frontend improvements! spent some time battling css for this relatively simple UI but it’s atleast somewhat pleasant to look at. will work on either image support or making it the app run in the background next.
a bunch of backend improvements: store timestamps for copy events more efficient message passing between frontend and backend Clear History functionality system tray (!) (pls ignore the missing icon in the tray, we don’t have an icon for the app yet) slightly better UI on the topic of UI, i’m getting around to deciding a color palette for the app. i will probably work more on the UI for a bit before switching gears to add more functionality (like image support). if i decide i want to ship early, v0.1 will probably go without image support and just get a lot of polish with text only functionality.
we got shortcuts we now have Ctrl+Shift+V as the shortcut to bring up Squirrel. (i know it’s used for “Paste as plain text” in some programs and used for “Paste in place” in photoshop but whatever). once up, you can select items from your history using arrow keys. pressing Return pastes the selected item into your last window. we’re having some issues with permissions but i’ll look into it. i’m now slowly simplifying the UI to be geared more towards improving user ergonomics and make it something that is not cluttered and easy to use. apart from this, i’ve cleaned up the code a bit removing stray debug prints and random commented code, it was getting out of hand. will write proper doc comments soon. todo i have to make the app load the user’s past clipboard history on startup lmao i totally forgot i have to start testing on linux, urgently. i feel i should make devlogs more often. even if nothing’s changed in the actual project, detailing plans helps me keep track of things personally. that’s pretty much it, stay tuned. edit: please ignore the VC_UNDEFINED keys in the input overlay in the attached video, it’s Enigo inputs not translating well.
more backend there isnt any significant change in the frontend but there’s a ton of backend refactoring and bugfixes. performance should be slightly better now with large copy/pastes. changelog: associate IDs with clipboard events so that we only have to pass IDs between the frontend and backend instead of the whole content. make paste operation more efficient ignore clipboard events caused by Squirrel itself (a bit hacky to achieve this but good enough) Quit button in tray icon menu so Squirrel can actually be closed (there was no way to close it before except killing it) make the shortcut to bring up Squirrel work in almost all situations refactor AppState + some other things more cleanup and comments anyways, attached image is the tentative color palette i might implement. i have no idea how to do this and which colors to use where or if it would even look good so i might just ditch it in the future. we’ll see. todo still have to test on linux and load history on app launch. probably will work on that next.
UI tweaks as i mentioned before, im in the process of simplifying the UI. i hid the native titlebar and made a custom one. also tweaked the shape of the window to feel more like a clipboard. that is all that’s changed significantly this devlog. development will probably slow down a little bit in the coming days because i have irl stuff to deal with.
custom scroll bar that is it, enjoy.
Frontend improvements we now have buttons on the clipboard entries so you can also use the mouse to perform the basic functions like copy, delete, etc. (pins wip). there have also been a bunch of UI improvements and tweaks in general. deleting feels instant. navigation is fixed (for the most part). Backend slight optimization in the pasting operation, plus a couple of fixes and doc comments.
Item search i’ve wanted to add this for a long time but it needed a lot of refactoring in the frontend so i put it off for later. it is now later. we have instant search. press / or any of the non shortcut keys to start searching. frontend logic has had a big refactor making navigation and other operations more predictable and less wonky. it took a bit of battling with the specifics of Svelte’s each loop and bind:this directive but it was worth it. there is still some cleanup that can be done, the code is not idiomatic by a long shot, but im happy we have a very essential feature complete. changelog: add search fix broken arrow navigation and copy/delete operations applying to wrong entries. make window size a bit bigger by default (might change later) make copy icon turn into a green checkmark so that there is some visual feedback on copying make the database file always save at the executable’s location. todo ! still need to test linux ! load history on launch app icon and branding
nothing significant. just docs and comments and cleanup. slowly making progress planning wise into loading the history at launch. the idea is to use a custom Tauri IPC Channel for incrementally streaming data to the frontend on app start. channels are supposedly faster for this and are meant for continuous messages like this in comparison to events. from the Tauri docs: Channels are designed to be fast and deliver ordered data. They are used internally for streaming operations such as download progress, child process output and WebSocket messages. i may implement a lazy loading system if i feel like it. i have nothing interesting to show so have a squirrel again
Ticked a couple of items off the todo list: Squirrel now loads the history on launch. doing this was easier than i expected, but it’s a very naive way to do it (literally just send all of the history on launch). we also now have a logo. im no graphic designer by any means so this is the best i could do. shows in the titlebar and when your history is empty. check the project banner for a larger version if you feel like it. i might change the logo in the future, i just wanted an icon. todo pinning items test on linux
wip dark theme support i want squirrel to use whatever theme the system is set to. currently it’s forced light mode but dark mode is something i’d be crucified for not adding. unfortunately, I in my infinite wisdom didn’t have the foresight to have consistent colors across even the light theme itself. there’s just random #aaa , #666 , etc colors everywhere where i went with what looked good. so work needs to be done to standardize the colors with css variables. then just modify the variables for dark theme accordingly. yes, i’m aware this is standard practice.
Dark theme! just glorious there isn’t a theme toggle button yet, it just goes off of your system’s theme for now. now that the colors are roughly standardized across the ui, tweaking the contrast and palette is a much more pleasant experience.
readme and polishing preparing to ship, writing docs, recording demos and stuff. there are a couple other things i want to sort out but i might ship in a few days.
more polish and minor fixes more readme refining, linux support clarity, and installation instructions. also, i completely forgot about the tray icon actually needing an image icon, so until now it was just blank. anyways, we now have an icon. next, we put out releases on github and ship, hopefully. unfortunately we have to wait until tomorrow for linux builds.
even more bugfixes ofcourse critical bugs pop up when im trying to release. the system tray icon wouldnt show up when running the single-file executable on any platform. that is now fixed. plus a couple more things have been done to make Squirrel behave like a good cross platform app, like storing the data in the OS’s appdata directory. there are some more things i would like to do but i think the app is in a releasable state and i’ve wanted to ship it for a while. I’ve set up the GitHub release and all the relevant instructions in the README. might be last devlog before ship #1.
Pins we now have basic entry pinning support. this was a bit less difficult than i thought it was going to be. but now you can pin an item and it always stays at the top of the list (unless you’re searching). anyways, that is one item ticked off the todo list. apart from that, i had to do some minor backend refactoring and reorganizing so that it is easier to build more upon. next? image and/or file copy support. this is one monumental task. i think the way we’ll approach this is by storing the entire file if it’s smaller than, say 5mb, and if it is larger, we just store the path to the file. we dont want to store the user’s 5gb video file they just copied. for images, i think the play is to generate a low quality thumbnail of the image to display in the app. for files, if it is a text file, we can show just the first 5 or so lines with a link to the file, other wise we’ll just give a link. until now, the code i’ve written sadly relies too much on the fact that every event is a text copy as we ignore everything else. it’s going to be a rather painstaking experience refactoring the codebase. the challenge is going to be keeping Squirrel quick and responsive while supporting all of this additional functionality.
Navigation improvements slight refactoring and bugfixes for frontend navigation. the navigation was kinda wonky before this and sometimes wouldn’t highlight the entry that was actually selected in the background. most of this devlog’s work was to make it so that what you see is what you get. also, a touch of color has been added to pinned entries (tentative).
CI dipped my toes into github workflows, messed around, an got check&lint workflows working on pull requests. will make a release workflow some time later. this change however, was only a part of this devlog’s time. Bad decisions catching up turns out, using clipboard_rs might’ve been the subpar choice for interfacing with the system clipboard. while clipboard_rs provides a easy way to listen to clipboard changes and get text from it, fetching raw clipboard data is buggy and inconvenient. when i sat down to work on image support, i was immediately brick-walled by how messy it is to just get raw data first. it would’ve been simple if i was building for just one target os but considering both windows and linux, it’s less than ideal. on top of this, the documentation for the crate is very lackluster. all this to say, i am very much debating migrating my clipboard stuff to using arboard . arboard doesnt provide direct functionality to listen to clipboard changes so i will have to implement that myself. but, it does have first class support for wayland. a very enticing choice, but we will see.
Sadness so i just found out that Tauri’s global shortcut plugin does not yet support Wayland, which is sad to discover this deep into development. but, there is an active PR addressing this issue , which is nice. what this means for Squirrel is that proper Wayland support will unfortunately have to wait until this is merged. the joys of using a not-yet-completely-matured framework i suppose. though it does make me feel a bit guilty for calling Squirrel “cross-platform”. in other news (changelog): Squirrel now has a --silent launch flag that makes it start with the window hidden. useful when the app is set to launch on system startup. Squirrel now makes sure there is only one instance of it running. The shortcut Ctrl+Shift+Del will clear history permanently. (i forgot about clear history functionality in the first ship even though the code for it existed, there just wasnt a button in the frontend to call it)
Closed 1 (one) issue moved the global launch hotkey logic from the frontend to the backend. it didn’t behave well in certain situations, failing to activate and bringing up the Squirrel window. Starting work on images we’re experimenting with images. the current functionality is very much caveman and needs a lot of attention to make it actually usable. i’ve decided to stick with clipboard_rs for now, we’ll see how that pans out.
Version bump and docs bumped the minor version. Squirrel is officially v0.2.0, yippi. plus, updated the README, adding more explanation about the Wayland issue. also showcased the pin feature. i’ll try to whip up a release workflow to add to my CI tomorrow. I’m debating whether i should ship v0.2.0. the only major change from 0.1.0 is the addition of pinning. i might wait until i have image support and ship later, or i might change my mind, im unsure.
Lots of refactoring (apologies for the uneventful devlog attachment, i have nothing interesting to show except just code) to make it a bit more manageable when adding image support, a bunch of refactoring and reorganizing has been done in the backend. like i’ve previously mentioned, the codebase leaned too hard into only supporting text events. this fixes that. today’s changes also make the internal communication a bit more efficient. there are a couple more places where performance can be improved. and we will need every bit of performance we can get when dealing with image data. Changelog (shoutout @Hridya for stardance utils, just discovered this) 5b3f285 refactor: move clipboard structures into separate file b3ab1c8 perf: only get required data from db when copying an item 69dc003 refactor: modify data types to enable addition of image support Release CI (wip) currently writing the Release workflow for Squirrel. i have to figure out how to upload the artifacts to a github release with proper versioning and all that. the strategy is to run the workflow whenever something is pushed to the release branch. that is all for today.
Progress on images we finally have some form of working image support in Squirrel. This required even more sweeping refactoring changes to the codebase, which was a bit painful and im sure the new code isn’t the best quality either and will bite me later, but we’ll deal with it when we deal with it. getting images is a bit slow however, as right now we’re storing the image as base64 encoded PNGs. i plan to use the SQLite blob type to just store the raw bytes and pass that back and forth to improve the performance a bit (maybe some sort of caching as well?). there are also other areas where that are to be improved but i wanted to get a somewhat working prototype as fast as i can. explaining the silence i’ve been distracted by some life stuff, making me neglect my projects a bit. i also got distracted by the ESP32, fun little device. that is where the 9 days went. but, expect me to work semi-regularly again. thanks for reading.
Bunch of things Image Improvements some performance enhancements with images. made the clipboard image data fetching happen in Tauri’s dedicated thread pool, effectively parallelizing the operation. this made image copying a lot faster. image support should be merged into master soon enough. Lazy loading we now have lazy loading for images. image data isn’t loaded until it is scrolled into view. makes startup quick. CI enabled Dependabot updates and optimized the lint workflows for PRs. previously, all of the project was lint+checked on PR when changing anything. now it only checks the part that’s changed (i.e. frontend or backend)
Image branch is merged yay, yippee even. next i need to implement a frontend cache to store the last X entries’ contents, particularly for images. the way it works right now, every time the images are re-rendered (due to being filtered by search, for example), content is fetched from the backend. this ofcourse, is less than ideal. but shouldnt be a lot of trouble to fix.
Basic image cache we now cache the last 32 images, fetching from the backend when required and updating the cache. made the image re-rendering issue instantly better. attached is the demo video i forgot to upload in the second to last devlog showing images in action. Performance images are a difficult thing to handle, especially when dealing with the system clipboard. i’ve made Squirrel as performant as i could to the best of my abilities, which is to say, it’s not the best. it isn’t as rich as i would like it to be, so i might return to this feature to improve it in the future. one restriction i’ve put on images to control some of the chaos is limiting the size to 5 megabytes, meaning any image above 5 megs isn’t registered. i could push that to 10, which is still practically instant. but Squirrel is intended to be a quick clipboard, and not dropbox. so this is my cheaty little escape. maybe i’ll relax the limit in the future if 5mb is really restrictive. Next? i’ll probably bump the minor version and ship (i wouldn’t dare a v1.0 currently). i’d say pinning and image support is enough to warrant a second ship. beyond that though, stands file(s) support, so a lot of decision making on how i want it to work to have a good balance of performance and usefulness. a bit of a lengthy devlog this one, and i appreciate if you read all that. but i wanted to clear up some things for myself and just have a frame of reference where Squirrel stands right now after returning from a development break.
Set for ship release is made, README updated. should be good to go.
Acting on feedback a shipwright recommended i change my banner to include a screenshot of the program. so we now have a shiny new banner that should look good everywhere on the site. this required me to figure out what dimensions the banner is shown at across the site. i’ve attached a rough template for banners. fitting everything inside the marked areas should make sure your banner isn’t cut off anywhere that matters. one reviewer rightfully couldn’t figure out how to quick paste items. this is a miss on my part because i didn’t really have a list of shortcuts anywhere and kind of just mentioned them in passing in the README. that has been rectified by adding a Shortcuts section to the readme.
Rudimentary file support we now have the most basic kind of file support there could be. which is just storing the path to the file. we then provide a link to the file in the frontend, clicking on which reveals the file in your explorer. we also now have tiny little icons on the entries which indicate the entry type. all icons thanks to https://lucide.dev/ files ofcourse, need a bit more work. right now, you cant really do much except revealing in explorer. i will work on adding copy and paste support for files next, as well as maybe improve the overall performance a bit.
Turns out, copy and paste support for files was a one line diff. also, Squirrel is now v0.4.0, yippee. anyways, moving swiftly on. Planning for a v1.0 Squirrel is now in a state where we have most of the major features i wanted it to have: support for essential clipboard data types, pinning and search. however, it is not quite in a v1.0 state. there are a bunch of things i want to add to polish up the program and make it feel sort of “complete”, which is mainly focusing on some basic configuration ability. since sensible defaults are hard to figure out, i’d rather let the user break things instead of being stuck with my arbitrary decisions. thus, i present the current planned feature list for v1: Configuration : enabling basic behavior customization through a config file (TOML most likely) Program exceptions : dont capture clipboard data on certain programs Auto delete/never store : ability to specify a “shelf life” for items, or whether to store them persistently at all. Disable specific types : ability to pick which kind of clipboard events to capture, i.e. only text or text and images, etc. Configurable image size threshold : currently locked to 5mb, this would allow to specify a custom value. (?) Custom data storage format : still torn on this, but there may be performance to be gained by moving to a data store more geared for our purposes. this list ofcourse, might change. implementing these features would make Squirrel much more flexible, and make it v1 worthy.
Configuration (wip) Squirrel now has a configuration file. squirrel.toml is created in the config directory of your OS (i.e. %appdata%/Squirrel on windows and /home/username/.config/Squirrel on linux), finally allowing some amount of customization support. right now, only the types and the max_image_size config options work. types allows you to choose which kind of clipboard items are captured/ignored. max_image_size is self explanatory. attached is the full config file. the remaining options require a bit of work to implement.
devlog attachment obligation: here is me pasting some files i copied a couple minutes ago after i copied stuff on top of that. that out of the way, devlog. Several things app theme is now configurable from config, so you are not stuck with the system theme if you want to change it. cleanup across the backend; comments, TODOs, error handling, and stuff of the sort. performance enhancement in the clipboard event emitter loop. bugfix in the same loop where the thread panicked if you copied something while the app was launching. merged the config branch. the remaining config options would be better to implement in their own branches. dependabot updates
Ignore programs you can specify programs in which Squirrel should not listen to clipboard events. this is useful when you’re working in a program wherein you need to use copy and paste a bunch. ignoring that program would keep your Squirrel history clean. also useful to ignore a program that you regularly copy secrets from. example of notepad being ignored:
(i genuinely have no idea what to show in the devlog attachment, nothing’s changed visually. so have this stupid ass screenshot.) Massive refactor, breaking changes now that i’ve given myself the liberty to rethink and redesign Squirrel’s data models and storage in a breaking fashion for v1, we have managed to make a good amount of improvements across the board. database schema has been modified to better suit current needs and make it possible to implement the features I desire for v1. it has been a very satisfying refactor. What’s new: use UNIX microsecond timestamp for event ids instead of relying on sqlite autoincrement. this allows us to immediately send a captured event to the frontend without having to await a db write to obtain the event id. this also eliminates the timestamp column for events since the id is also the timestamp. a dedicated BLOB column for image entries to store raw image bytes instead of b64 encoded strings. this makes images weigh about ~33% lighter. decent perf boost. new expires_at column to store when an entry expires. pinned entries have an expiry of NULL . provides the base to actually implement expiring entries. get rid of ClipboardEventNotice since we no longer do the notify frontend -> write to db -> send data to frontend dance. it is now simply send whole event to frontend -> write to db . we enjoy simplifications. (!) as it stands now, old data (if it exists) would immediately be wiped when launching Squirrel v1. i could write some migration code but we’ll see. maybe clipboard data isn’t important enough to bother with migration. Next: actually implement entry expiration: should be trivial, just delete expired entries on launch. ephemeral/persistent toggle: this one is a bit tricky, and will involve some in memory database shenanigans. more details in the devlog when i implement this.
Item expiry and pin-preservation expired items are now automatically deleted on program startup. an entry is considered expired when the current time is more than its expires_at value. when pinned, the expires_at attribute is nulled, meaning this entry will never expire. the “Clear all” shortcut Ctrl+Shift+Del now respects pinned entries. it clears everything but leaves pinned entries untouched. Next the ephemeral db shenanigans. also, i have decided that Squirrel needs a settings panel in the frontend for easier config modification. that may or may not happen but it is tempting to do it.
History persistence configuration now works. setting it to false means history is not retained between sessions. comes with true as default. pinned entries always persist. attachment shows the behavior when persistence is off. Implementation i ended up deciding not to do the in memory database method for this since it was a bit too much added complexity which could be avoided by just adding an additional is_persistent column to the db. im not the happiest about how i’ve implemented this right now but im willing to take that hit right now if it means i dont have to deal with databases. Next all of the config options are now implemented. we are very close to v1.0. expect progress to be rather slow from here on out. i’ve had to divert my attention towards other things and haven’t been able to spend a lot of time working on my projects. maybe i will work on a settings panel. depends on how much work it requires. it’s a maybe. i may just ship it as it stands right now.
v1.0.0 It’s official. Squirrel is now v1. devlog time is adding logging, updating readme, fixing some small tidbits and polishing up some areas of the app. Squirrel now prints pretty logs to console when running in development mode and writes logs to a file if running in release. Project status i realistically can not get a GUI settings panel done due to me needing to divert my attention to more important life stuff. this right here is probably going to be the extent of work done on Squirrel in stardance. i definitely do plan on working on this in the long term. for example, im not entirely happy and satisfied with the current UI, and global hotkey still does not work on wayland. but right now, more pressing issues are at hand and i cannot give it my all on this project. that said, i do believe that Squirrel is in a very usable 1.0 state, which was my goal. i might push minor updates if the reviews call for fixes/improvements, but definitely no major features. thanks for reading if you made it here.
Ships:
v0.1.0 Squirrel is a clipboard manager that is meant to be simple and intuitive. It remembers all the text you copy allowing you to paste whatever into wherever. You can also quickly search through your history. Squirrel is meant to be cross-platform, but for this release, Linux support on Wayland is very iffy (X11 is fine for the most part). I would highly recommend using Windows for testing this ship, sorry for the inconvenience. Expect potentially better support next ship.
v0.3.0 Squirrel is a clipboard manager that is meant to be simple and intuitive. 2 new features in this version, namely pinning and image support. There are performance improvements as well as slight visual tweaks. Read the README for more info.
v1.0.0 Squirrel is a clipboard manager for Windows and X11 Linux that is meant to be simple and intuitive. This major release overhauls the data storage schema to be more efficient, faster, and reliable. There are significant performance improvements. This release also adds configurability to Squirrel, allowing basic but much needed customization, and polishes up the overall app. Check the README for more information....
|
1792986543.9706123
|
1793072943.9706123
|
|
33983
|
ValoGuess by @NHero | Stardance
|
NHero
|
1
|
104.0
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-20T14:59:44Z", "hours": 104.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I built ValoGuess , a real-time multiplayer Valorant guessing game inspired by guessing videos on youtube (VCT Pacific). Players can challenge friends in 1v1 matches, eliminate agents, ask questions, and race to identify their opponent’s secret agent. It includes party lobbies, friend invites, real-time chat, player profiles, and match history. The most challenging part was building the real-time backend: synchronizing game state between players, handling disconnects and reconnections, hiding secret agents from opponents, and managing live state with Socket.IO and Redis. I’m proud of building the full experience from the game UI to the backend architecture, with separate Next.js and Socket.IO server repositories. Try it: Visit https://valoguess.fun , sign in or continue as a guest, and invite a friend for a match. Atleast one extra friend is needed or a different browser or incognito tab.", "repo": "https://github.com/valoguess/valoguess", "demo": "https://valoguess.fun"}]...
|
[{"post_id": 81260, "ts": "202 [{"post_id": 81260, "ts": "2026-10-20T14:40:52Z", "hours": 1.8425, "text": "Devlog 12 So I think this one is the last before ship, I promise. 😂🥹 Fixed some bugs here and there Added readme Added some bg and showcase photos Added a layout for the home pages (lobby, settings, leaderboard, match history) where the top navbar and the friend sidebar is given to all. I think that’s it. I got no friends, or the friends I have aren’t like best of friends So I wasn’t able to test the game on scale. Feel free to open a issue in github or message me on slack"}, {"post_id": 81097, "ts": "2026-10-19T21:13:57Z", "hours": 10.1267, "text": "Devlog 11 So I have done lots of stuff and this is the last devlog before the first ship. Little sleepy rn as its 2:35 am my time, so I will wrap up fast. Added pino in Nextjs (Its a logger) Added caching wherever possible in nextjs using the cacheLife Added auth refresh event so if the name is changed it doesn’t need socket reconnect Optimised some code in socket server and also nextjs. Games getting saved to DB and there is a career history page now. Mostly did fixes of stuff and redesigned some elements in the lobby page. Like there is nothing else to talk about I’m mostly fixed stuff. I gotta sleep, have to ship the project too maybe I do it after waking up because readme is not ready yet. I think I’m gonna do after waking up so tired rn"}, {"post_id": 79776, "ts": "2026-10-15T11:01:26Z", "hours": 10.6203, "text": "Devlog - 10 I will keep this devlog sweet and short as I wanna ship this project as soon as possible as It has taken a lot of time now. I added some more rate limiting remove game Id / party id payload where neccessary from client in socket server as game/party id can be retrieved from player stored in redis. I’m directly getting friendships from db instead of relying on nextjs api in the socket server to show the initial friends list with presence (online/offline status). Removed TTL from party and game as they may get deleted mid game (prev ttl was 10 mins). I have also added token refreshing in socket server as socket server only verifies token once so now when the token refreshes (only for when user details are mutated) socket disconnects and connects, I know this is a bad logic I will change that but 10h 37m will be logged so I don’t wanna waste any more time , so it will be in next devlog Using AVIF instead of PNG for Agents Banner & Icon Added new fields to user (tagline, banner, usernamedUpdatedAt, nameUpdatedAt) Cleaned up many of the files in the frontend party Added logic for If user changes their avatar it should delete the old image in cloudinary Added Match ending design ENV are now accessed from ENV.ts Removed console.logs etc from nexjs Fixed some bugs."}, {"post_id": 78076, "ts": "2026-10-09T14:19:49Z", "hours": 9.7719, "text": "Devlog - 9 NextJS I added upload avatar in the settings page, user uploads an avatar and crops it accordingly , max file size limit is 5mb also the image gets uploaded to cloudinary and the secure url of the image is stored in db Changed the lobby UI to make it less cluttered Now there are drawers for gamemode settings and party stuff Changed the friends sidebar to be attaced to the right wall and closed and when you open it , it comes out of the screen not occupieing any space. Made a UI for FREEFORM questionMode Added a animated starting screen. Socket Server Added a new questionMode inside the Guess Agent gamemode now you can have freeform questions or preset Preset is same as before you will have a preset of questions to choose from and all its all like before Freeform is different you will have two buttons instead of questionPanel, you will have make guess and consume no. This gamemode is meant to be played in a vc like discord or any of your choice you can ask questions to the opponent direclty if there is a no you can just consume no and if you wanna guess you can guess. its like a offline game but you can count the nos and guess and have a agent panel to deduce Added a game starting phase where some details are created to show to the frontend. Added game cleanup functions, not perfect but will do for now Added a new event CONSUME_NO to consume no for questionMode Made some changes to type to adjust for freeform question mode EXTRA Added rate limiting in some parts In socket server rate limiting is token bucket and in nextjs rate limiting is sliding window counter (somewhat strict rate limiting in guest login and magic link) The rate limiting is handled by the same redis used for game states and stuff Fixed some bugs here and there. I know this devlog doesn’t feel personal and I only talk about the stuff I did, its because I wanna Ship this project as soon as possible and get done with it and move on to something else, because projects like this never end and you have to decide when to stop. I think next devlog will be the last devlog before the first ship"}, {"post_id": 76249, "ts": "2026-10-02T21:25:10Z", "hours": 9.7156, "text": "Devlog - 8 Big devlog, here we go again. Lets talk about nextjs first. So I added magic link to the app as the feedback I received was I don’t wanna use my google account as I don’t the trust the website enough to use it and I also want to use all the features so guest won’t work. This pushed me to add somewhat of a email login. I dont like password login so I wanted to add passwordless login and it wasn’t a debate I just picked one which is magic link. I am using resend for sending emails and i already have a domain for the app so using that for send email with auth@mydomain I created a template in resend dashboard itself so i can direclty use it in my nextjs app. Now lets talk about the big thing which made this a long devlog !!! Drum Roll please 🥁🥁🥁 I decided to restructure many parts of my socket server because of scalability as my previous architecture wouldn’t have survived If i added more gamemodes and all. What were the flaws Room was acting like if it was the party and the game Current gamemode is available is guess the agent so all the connecting modules were designed based on that which would have made adding other gamemodes impossible. There was no generic game module it was just Guess the Agent What I did Changed room to game and separated game ( previously room ) from party and added a separate events and module for party and party gets stored in redis as well. Inside the game module added a core folder where core mechanics (listener, types, service) of each game regardless of gamemode lives. Each gamemode has its own folder inside game containing the logic specific to that game. Redis player now has a partyId element too. Improved player presence (connection and disconnect) and using switch statements in places where if the mode is different some logic might be different. Why did it took so much time and What I learnt. Because when I started the restructure I didn’t know how my architecture would look like or what would work ( still haven’t tested anything ). So I researched some stuff but some stuff you decide along the way. I learnt that no matter what the project is and what you decide at the start that you are gonna build there will always be a time where the plans fail and we have to decide should we go through with it or suffer in the future or should we just focus right now and work hard so that in the future it all comes back to us with a lots of happiness!!! Cheers, Neerav"}, {"post_id": 74034, "ts": "2026-09-26T15:51:51Z", "hours": 10.095, "text": "Devlog - 7 Another Long Devlog Time So I was setting up my project to be deployed on the nest container that I have since nest only gives public ipv6 I couldn’t host my nextjs app on vercel because then I wouldn’t have been able to connect to my postgres database which was on nest as vercel dont have ipv6 support so I moved my nextjs to nestjs and It caused me hell lot of problems and bugs. First of all had to make sure nextjs, postgres and socket server were running on same docker network. My nest container was crashing when building the nextjs for docker. Had to move building process to my laptop then push the image to ghcr.io And some silly mistakes that took me long time to fix. Lets talk about the project what I update in that So first of all made a presence for managing friends online status. Added logic to connection and disconnection events of player socket. As when players connects through socket it should know whom his friends and what friend requets he got and what friends are currently online and also if he is reconnecting (For now 1minute reconnect window) the socketId should be updated in the needed area (room and player redis store). When the socket disconnects, set the socketId in player redis store to null . After the reconnect window is over check if he is in a room, if yes remove him from the room and in both cases delete the player record from redis . Also lets expand on connection syncFriends the socket requests data from an internal api route only accessible through the socket for what friendship records are there and formats it in friends: [], requests: [ incoming: [], outgoing: [] ] Then socket server retrieves all the playes using their playerid from redis via mget and then returns the same object structure but in friends its adds a online: true/false to the player objects Also removed polling for friendships as now socket does them all. So there is less db calls now. Fixed few bugs too. Now let me tell you a funny story. When testing stuff in prod, I was confused why stuff wasn’t working because it was working fine during development then i remembered I didn’t update the .env file in prod. It may have cut some years from my lifetime."}, {"post_id": 71723, "ts": "2026-09-21T11:48:59Z", "hours": 9.9617, "text": "Devlog - 6 This is gonna be a long devlog. Lets start with the frotend I committed the prev work from the previous devlog as mentioned there. Added welcome, settings page, Added friends sidebar with realtime functionalities. Added a friends store to store incoming friends invites. Fixed some file structure to have protected routes inside (protected). And mostly this covers it for frotend Now lets talk about backend that made this devlog of 10 hours Backend I first connected the socket with the player from the db via jwt tokens. Stored some player data like id, username inside socket.data. Then I changed my room mapper implementation to use player Id instead of socket Id and messed up in some places where socket Id was still getting passed to room mapper which made me spent so much time looking for what is the issue why isn’t my room details getting sent to me and I was looking in nextjs frontend for the issue. I spent so much time finding this bug I added some more events for player invites and added a new redis key:value pair -> player:playerid to store player details like id, username, socket id, roomId, lastHeartBeatAt also removed lastHeartBeatAt and reconnectToken from room player. Added events for invite, server event of invite:sync and made realtime invite work which took me forever. Made some changes in connection event so it handles reconnection Finally let me tell you something when visting the website if the thing looks small the implementation of that thing takes so much time. Bro Literally the friends sidebar took so much code to make in the frontend and in the backend and in the socket server as well. like that small piece of the page took me so much time to make which also made this devlog So long. Incountered so many bugs along the way. They were all silly mistakes some were logic error but most were silly mistakes as there are so many files in the project now its hard to find some things."}, {"post_id": 68663, "ts": "2026-09-15T14:28:10Z", "hours": 9.7922, "text": "Devlog 5 So I am now using drizzle with postgres and I also took some time to tinker with it and understand it a little better. I am also using better auth with google signIn and anonymous login. In the user i have username and name , username is for adding friends or locating a user, name is to be displayed , username is unique, name isn’t. Created the db model with friends support and matches history. We can add friends in the game also added user settings to customise stuff. Project is starting to look like something. All the drizzle + backend part that i have done in the period is committed and pushed but the frontend part still remains to be committed."}, {"post_id": 61087, "ts": "2026-09-03T20:08:51Z", "hours": 9.3056, "text": "Devlog 4 So first of all I switched from using npm to pnpm and updated the docker file accordingly for the socket server. Then I started working on adding users / db functionality in the nextjs app. I created login and register page with two options for signIn -> google or guest. I started tinkering with prisma and better auth and the prisma8 has just come so I started setting it up and had made the schema and had written up some services too but then when I tried to logIn i got few problems which I researched and searched and found out that betterAuth hasn’t adjusted to prism8. So I did what I should have done before, I switched to drizzle. Around 3-4 or more hours were wasted!. Now I’m using drizzle and have setup the schema and tables and also better auth in it and the signIn are working. Now I have to create routes or server Actions to retrieve data or send data. Now the games will be saved and stored once finished and user will able to see it in match history."}, {"post_id": 51021, "ts": "2026-08-20T14:43:00Z", "hours": 5.5508, "text": "Devlog 3 Backend Socket Server Made few changes to setting type and added a questionPool in gameState Settings now have a option to change totalQuestions and a randomly generated questionPool from the totalQuestions Removed spectator logic as not planning on pursuing it right now Also added a heartbeat event which supplies heartBeat every 5 seconds or so and if there is no heartBeat provided by the player for over 30 seconds the player gets removed from the room Now Frontend Redesigned the lobby page and home page If you open the game for the first time it asks for the name which is currently stored in localstorage for a guest user. When users are added then people would be able to login using google and save their details in database. For now nothing is stored , only gameState are persistent for the duration of the game in redis and after few minutes of inactivity in the room , the room expires via ttl. Also added SEO Optimisations. Future Plan I will either work on adding more gamemodes or adding the user authentication stuff using postgresql and prims direclty in nextjs After the auth has been added then I will publish the project so that it has atleast some complete features and users can see their stats and prev games results"}, {"post_id": 39462, "ts": "2026-08-02T12:58:48Z", "hours": 8.5258, "text": "Devlog 2 Making this devlog after a long time of doing all this work, the frontend part is still uncommited in github though Lets talk about backend first -> I first of all was using playerId for the routes to verify the user, but now I’m using socketId And also for reconnection I’m now using a reconnectToken which is created on the socket server and given to the frontend to it can pass it when reconnecting. Also I added a ROOM_KICK event. And I added docker setup too but its still buggy Changed Winning logic so that first correct guess wins Now Frontend I designed the pages using AI because I am not a good designer rather I am a good coder you can say, because if there is a already made design, I can make a similar one using tailwind and shadcn and other UI libraries I added socket setup for the frontend which goes as follow src/socket -> index.ts, emitter.ts, events.ts src/components/SocketProvider.tsx Socket Provider has the listeners emitter.ts has small functions that can be directly used inside tsx instead of importing socket There are 3 pages currently -> /, /lobby, /play"}, {"post_id": 30879, "ts": "2026-07-18T20:44:34Z", "hours": 8.6403, "text": "Devlog 1 So I’ve been working on the socket server for this game for the past couple of days. What I’ve learned so far is that game logic is sometimes so frustrating like there can be so many edge cases you have to think about and there can be many nested if else. So my tech stack for the socket server is: Socket.io IoRedis (redis hosted using docker) Zod and node httpServer Ofcourse everything is written in typescript. I didn’t made separate devlogs because I forgot, sorry for that Here’s what I did I made the folder structure moduler having different modules for different logic : room, game, question Shared files are in shared folder Each module has its own listener, service, schema with some having util/helper file I first worked on room then game then question Some things are still left to do, but first I would like to make some of the frontend"}]...
|
Title: ValoGuess by @NHero | Stardance
Devlogs:
D Title: ValoGuess by @NHero | Stardance
Devlogs:
Devlog 1 So I’ve been working on the socket server for this game for the past couple of days. What I’ve learned so far is that game logic is sometimes so frustrating like there can be so many edge cases you have to think about and there can be many nested if else. So my tech stack for the socket server is: Socket.io IoRedis (redis hosted using docker) Zod and node httpServer Ofcourse everything is written in typescript. I didn’t made separate devlogs because I forgot, sorry for that Here’s what I did I made the folder structure moduler having different modules for different logic : room, game, question Shared files are in shared folder Each module has its own listener, service, schema with some having util/helper file I first worked on room then game then question Some things are still left to do, but first I would like to make some of the frontend
Devlog 2 Making this devlog after a long time of doing all this work, the frontend part is still uncommited in github though Lets talk about backend first -> I first of all was using playerId for the routes to verify the user, but now I’m using socketId And also for reconnection I’m now using a reconnectToken which is created on the socket server and given to the frontend to it can pass it when reconnecting. Also I added a ROOM_KICK event. And I added docker setup too but its still buggy Changed Winning logic so that first correct guess wins Now Frontend I designed the pages using AI because I am not a good designer rather I am a good coder you can say, because if there is a already made design, I can make a similar one using tailwind and shadcn and other UI libraries I added socket setup for the frontend which goes as follow src/socket -> index.ts, emitter.ts, events.ts src/components/SocketProvider.tsx Socket Provider has the listeners emitter.ts has small functions that can be directly used inside tsx instead of importing socket There are 3 pages currently -> /, /lobby, /play
Devlog 3 Backend Socket Server Made few changes to setting type and added a questionPool in gameState Settings now have a option to change totalQuestions and a randomly generated questionPool from the totalQuestions Removed spectator logic as not planning on pursuing it right now Also added a heartbeat event which supplies heartBeat every 5 seconds or so and if there is no heartBeat provided by the player for over 30 seconds the player gets removed from the room Now Frontend Redesigned the lobby page and home page If you open the game for the first time it asks for the name which is currently stored in localstorage for a guest user. When users are added then people would be able to login using google and save their details in database. For now nothing is stored , only gameState are persistent for the duration of the game in redis and after few minutes of inactivity in the room , the room expires via ttl. Also added SEO Optimisations. Future Plan I will either work on adding more gamemodes or adding the user authentication stuff using postgresql and prims direclty in nextjs After the auth has been added then I will publish the project so that it has atleast some complete features and users can see their stats and prev games results
Devlog 4 So first of all I switched from using npm to pnpm and updated the docker file accordingly for the socket server. Then I started working on adding users / db functionality in the nextjs app. I created login and register page with two options for signIn -> google or guest. I started tinkering with prisma and better auth and the prisma8 has just come so I started setting it up and had made the schema and had written up some services too but then when I tried to logIn i got few problems which I researched and searched and found out that betterAuth hasn’t adjusted to prism8. So I did what I should have done before, I switched to drizzle. Around 3-4 or more hours were wasted!. Now I’m using drizzle and have setup the schema and tables and also better auth in it and the signIn are working. Now I have to create routes or server Actions to retrieve data or send data. Now the games will be saved and stored once finished and user will able to see it in match history.
Devlog 5 So I am now using drizzle with postgres and I also took some time to tinker with it and understand it a little better. I am also using better auth with google signIn and anonymous login. In the user i have username and name , username is for adding friends or locating a user, name is to be displayed , username is unique, name isn’t. Created the db model with friends support and matches history. We can add friends in the game also added user settings to customise stuff. Project is starting to look like something. All the drizzle + backend part that i have done in the period is committed and pushed but the frontend part still remains to be committed.
Devlog - 6 This is gonna be a long devlog. Lets start with the frotend I committed the prev work from the previous devlog as mentioned there. Added welcome, settings page, Added friends sidebar with realtime functionalities. Added a friends store to store incoming friends invites. Fixed some file structure to have protected routes inside (protected). And mostly this covers it for frotend Now lets talk about backend that made this devlog of 10 hours Backend I first connected the socket with the player from the db via jwt tokens. Stored some player data like id, username inside socket.data. Then I changed my room mapper implementation to use player Id instead of socket Id and messed up in some places where socket Id was still getting passed to room mapper which made me spent so much time looking for what is the issue why isn’t my room details getting sent to me and I was looking in nextjs frontend for the issue. I spent so much time finding this bug I added some more events for player invites and added a new redis key:value pair -> player:playerid to store player details like id, username, socket id, roomId, lastHeartBeatAt also removed lastHeartBeatAt and reconnectToken from room player. Added events for invite, server event of invite:sync and made realtime invite work which took me forever. Made some changes in connection event so it handles reconnection Finally let me tell you something when visting the website if the thing looks small the implementation of that thing takes so much time. Bro Literally the friends sidebar took so much code to make in the frontend and in the backend and in the socket server as well. like that small piece of the page took me so much time to make which also made this devlog So long. Incountered so many bugs along the way. They were all silly mistakes some were logic error but most were silly mistakes as there are so many files in the project now its hard to find some things.
Devlog - 7 Another Long Devlog Time So I was setting up my project to be deployed on the nest container that I have since nest only gives public ipv6 I couldn’t host my nextjs app on vercel because then I wouldn’t have been able to connect to my postgres database which was on nest as vercel dont have ipv6 support so I moved my nextjs to nestjs and It caused me hell lot of problems and bugs. First of all had to make sure nextjs, postgres and socket server were running on same docker network. My nest container was crashing when building the nextjs for docker. Had to move building process to my laptop then push the image to ghcr.io And some silly mistakes that took me long time to fix. Lets talk about the project what I update in that So first of all made a presence for managing friends online status. Added logic to connection and disconnection events of player socket. As when players connects through socket it should know whom his friends and what friend requets he got and what friends are currently online and also if he is reconnecting (For now 1minute reconnect window) the socketId should be updated in the needed area (room and player redis store). When the socket disconnects, set the socketId in player redis store to null . After the reconnect window is over check if he is in a room, if yes remove him from the room and in both cases delete the player record from redis . Also lets expand on connection syncFriends the socket requests data from an internal api route only accessible through the socket for what friendship records are there and formats it in friends: [], requests: [ incoming: [], outgoing: [] ] Then socket server retrieves all the playes using their playerid from redis via mget and then returns the same object structure but in friends its adds a online: true/false to the player objects Also removed polling for friendships as now socket does them all. So there is less db calls now. Fixed few bugs too. Now let me tell you a funny story. When testing stuff in prod, I was confused why stuff wasn’t working because it was working fine during development then i remembered I didn’t update the .env file in prod. It may have cut some years from my lifetime.
Devlog - 8 Big devlog, here we go again. Lets talk about nextjs first. So I added magic link to the app as the feedback I received was I don’t wanna use my google account as I don’t the trust the website enough to use it and I also want to use all the features so guest won’t work. This pushed me to add somewhat of a email login. I dont like password login so I wanted to add passwordless login and it wasn’t a debate I just picked one which is magic link. I am using resend for sending emails and i already have a domain for the app so using that for send email with auth@mydomain I created a template in resend dashboard itself so i can direclty use it in my nextjs app. Now lets talk about the big thing which made this a long devlog !!! Drum Roll please 🥁🥁🥁 I decided to restructure many parts of my socket server because of scalability as my previous architecture wouldn’t have survived If i added more gamemodes and all. What were the flaws Room was acting like if it was the party and the game Current gamemode is available is guess the agent so all the connecting modules were designed based on that which would have made adding other gamemodes impossible. There was no generic game module it was just Guess the Agent What I did Changed room to game and separated game ( previously room ) from party and added a separate events and module for party and party gets stored in redis as well. Inside the game module added a core folder where core mechanics (listener, types, service) of each game regardless of gamemode lives. Each gamemode has its own folder inside game containing the logic specific to that game. Redis player now has a partyId element too. Improved player presence (connection and disconnect) and using switch statements in places where if the mode is different some logic might be different. Why did it took so much time and What I learnt. Because when I started the restructure I didn’t know how my architecture would look like or what would work ( still haven’t tested anything ). So I researched some stuff but some stuff you decide along the way. I learnt that no matter what the project is and what you decide at the start that you are gonna build there will always be a time where the plans fail and we have to decide should we go through with it or suffer in the future or should we just focus right now and work hard so that in the future it all comes back to us with a lots of happiness!!! Cheers, Neerav
Devlog - 9 NextJS I added upload avatar in the settings page, user uploads an avatar and crops it accordingly , max file size limit is 5mb also the image gets uploaded to cloudinary and the secure url of the image is stored in db Changed the lobby UI to make it less cluttered Now there are drawers for gamemode settings and party stuff Changed the friends sidebar to be attaced to the right wall and closed and when you open it , it comes out of the screen not occupieing any space. Made a UI for FREEFORM questionMode Added a animated starting screen. Socket Server Added a new questionMode inside the Guess Agent gamemode now you can have freeform questions or preset Preset is same as before you will have a preset of questions to choose from and all its all like before Freeform is different you will have two buttons instead of questionPanel, you will have make guess and consume no. This gamemode is meant to be played in a vc like discord or any of your choice you can ask questions to the opponent direclty if there is a no you can just consume no and if you wanna guess you can guess. its like a offline game but you can count the nos and guess and have a agent panel to deduce Added a game starting phase where some details are created to show to the frontend. Added game cleanup functions, not perfect but will do for now Added a new event CONSUME_NO to consume no for questionMode Made some changes to type to adjust for freeform question mode EXTRA Added rate limiting in some parts In socket server rate limiting is token bucket and in nextjs rate limiting is sliding window counter (somewhat strict rate limiting in guest login and magic link) The rate limiting is handled by the same redis used for game states and stuff Fixed some bugs here and there. I know this devlog doesn’t feel personal and I only talk about the stuff I did, its because I wanna Ship this project as soon as possible and get done with it and move on to something else, because projects like this never end and you have to decide when to stop. I think next devlog will be the last devlog before the first ship
Devlog - 10 I will keep this devlog sweet and short as I wanna ship this project as soon as possible as It has taken a lot of time now. I added some more rate limiting remove game Id / party id payload where neccessary from client in socket server as game/party id can be retrieved from player stored in redis. I’m directly getting friendships from db instead of relying on nextjs api in the socket server to show the initial friends list with presence (online/offline status). Removed TTL from party and game as they may get deleted mid game (prev ttl was 10 mins). I have also added token refreshing in socket server as socket server only verifies token once so now when the token refreshes (only for when user details are mutated) socket disconnects and connects, I know this is a bad logic I will change that but 10h 37m will be logged so I don’t wanna waste any more time , so it will be in next devlog Using AVIF instead of PNG for Agents Banner & Icon Added new fields to user (tagline, banner, usernamedUpdatedAt, nameUpdatedAt) Cleaned up many of the files in the frontend party Added logic for If user changes their avatar it should delete the old image in cloudinary Added Match ending design ENV are now accessed from ENV.ts Removed console.logs etc from nexjs Fixed some bugs.
Devlog 11 So I have done lots of stuff and this is the last devlog before the first ship. Little sleepy rn as its 2:35 am my time, so I will wrap up fast. Added pino in Nextjs (Its a logger) Added caching wherever possible in nextjs using the cacheLife Added auth refresh event so if the name is changed it doesn’t need socket reconnect Optimised some code in socket server and also nextjs. Games getting saved to DB and there is a career history page now. Mostly did fixes of stuff and redesigned some elements in the lobby page. Like there is nothing else to talk about I’m mostly fixed stuff. I gotta sleep, have to ship the project too maybe I do it after waking up because readme is not ready yet. I think I’m gonna do after waking up so tired rn
Devlog 12 So I think this one is the last before ship, I promise. 😂🥹 Fixed some bugs here and there Added readme Added some bg and showcase photos Added a layout for the home pages (lobby, settings, leaderboard, match history) where the top navbar and the friend sidebar is given to all. I think that’s it. I got no friends, or the friends I have aren’t like best of friends So I wasn’t able to test the game on scale. Feel free to open a issue in github or message me on slack
Ships:
I built ValoGuess , a real-time multiplayer Valorant guessing game inspired by guessing videos on youtube (VCT Pacific). Players can challenge friends in 1v1 matches, eliminate agents, ask questions, and race to identify their opponent’s secret agent. It includes party lobbies, friend invites, real-time chat, player profiles, and match history. The most challenging part was building the real-time backend: synchronizing game state between players, handling disconnects and reconnections, hiding secret agents from opponents, and managing live state with Socket.IO and Redis. I’m proud of building the full experience from the game UI to the backend architecture, with separate Next.js and Socket.IO server repositories. Try it: Visit https://valoguess.fun , sign in or continue as a guest, and invite a friend for a match. Atleast one extra friend is needed or a different browser or incognito tab....
|
1793051402.1555357
|
1793137802.1555357
|
|
18188
|
Onara by @aarushk | Stardance
|
aarushk
|
1
|
103.77
|
504
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-19T22:28:48Z", "hours": 44.0, "multiplier": 19.06, "payout": 504, "blessing": "neutral", "text": "I made Onara, an AI website builder for local businesses. It helps contractors turn their Google Business Profile, or manually entered business info, into a live website with copy, design, SEO, photos, contact forms, and a public URL. The hardest part was connecting everything together: the Next.js app, Supabase auth/database, Stripe billing, the FastAPI AI pipeline, Cloudflare deployment, GitHub backups, and the revision system. Getting the AI output to be good and not broken was also challenging. I’m proud that it is not just a mockup anymore. Users can sign in, search or enter a business, generate a site, revise it, manage billing, and keep their generated code backed up. To test it, sign up, search for a local business, confirm the details, pick a style, and start a build. After the site generates, try the revision page and ask for a small change like “make the hero CTA bigger.”", "repo": "https://github.com/Ak123yay/Onara/", "demo": "https://onara.tech"}]...
|
[{"post_id": 27459, "ts": "202 [{"post_id": 27459, "ts": "2026-07-13T01:25:29Z", "hours": 9.7311, "text": "First generated site!!! Pipeline finally works!"}, {"post_id": 23034, "ts": "2026-07-05T19:25:57Z", "hours": 12.2622, "text": "turning onara into Google Business Profile → website → quote form → missed-call recovery → lead inbox → booked job follow-up"}, {"post_id": 17247, "ts": "2026-06-27T23:26:00Z", "hours": 37.7717, "text": "Trying to make the pipeline generate a proper output. Polishing up the application."}, {"post_id": 12202, "ts": "2026-06-19T22:22:13Z", "hours": 8.2644, "text": "devlog 003 - making Onara launch-ready Date: 2026-06-19 Since devlog 002, I mostly worked on turning Onara from “it works” into something closer to launch-ready. what I worked on billing + accounts I added more real account controls: cancel subscription from billing plan limits better account page better checkout layout Google-login warning if someone tries password login on a Google account Google account -> use Continue with Google Password account -> normal email/password login generated sites I worked on making the sites Onara creates more useful after launch: contact form lead emails better email HTML Pro code download cancellation placeholder pages Google Reviews refresh job support email surfaces contact form -> Onara lead email -> site owner inbox pipeline fixes I fixed more backend/build issues: longer pipeline timeout better health monitor support fixed /health HEAD checks fixed broken generated HTML cases improved Google Maps region filtering back toward DC / VA GET /health -> 200 OK HEAD /health -> 200 OK launch cleanup I added launch stuff that real products need: privacy policy terms of service support page favicon/logo polish SEO metadata .env.example updates docs for production fixes AI + training data I also added the start of a cleaner AI improvement system: user consent copy opt-out/delete handling training example storage QA-approved examples only no saving random bad generated sites into RAG good QA result -> redact -> save as training example bad result -> do not save biggest change Onara is not just generating sites now. It is starting to act like a real app with billing, support, cancellation, reviews, contact leads, account limits, and safer AI improvement rules. still left finish production deploy polish make generated site quality more consistent keep fixing slow render/build issues launch testing outreach assets"}, {"post_id": 11090, "ts": "2026-06-18T04:09:31Z", "hours": 26.8906, "text": "devlog 002 - the fake flow became the real app Date: 2026-06-18 Sorry abt not posting a devlog in a while, completely forgot i had to do them! (too locked in lol). Onara moved from prototype to real product system. Devlog 001 ended with the app shell, Supabase setup, and mock agent progress. Since then, the missing backend got built: FastAPI, real agents, deployment, revisions, billing, and account gating. Find -> Confirm -> Style -> Generate now connects to the actual pipeline. what I built FastAPI backend /generate and /health job queue + dedupe SSE progress stream dashboard build resume Cloudflare Tunnel + PM2 Next.js -> FastAPI -> agents -> Cloudflare -> Supabase AI pipeline I added the real 10-agent flow: Analyst, Content Writer, Style Agent, Planner, Prompt Engineer, Code Generator, Debugger, SEO Agent, QA, and Mobile check. Agent 6 now has a plan-gated model picker. Free -> Onara default Starter -> Copilot options Trial / Pro -> full access I also added shared AI clients for NVIDIA NIM, Ollama, and GitHub Copilot SDK. z-ai/glm-5.1 -> llama-4-maverick -> gemma4:e4b RAG and deployment I added RAG with ChromaDB, BM25 search, seeded HTML/CSS/JS patterns, and contractor layout examples. Deployment now does this: parse generated HTML split component files back up code to GitHub deploy to Cloudflare Pages save metadata in Supabase generated site -> GitHub -> Cloudflare -> Supabase revisions The revision page became a real workflow with: revision threads queued work log auto-pick or manual components changed-file summaries rollback UI retry without charging failed builds { instruction : \" make the hero CTA bigger \" , componentSelection : { mode : \" auto \" } } The UI also got cleaner: denser chat, better work log placement, flatter composer, and Onara styling. billing I added real billing: Stripe checkout sessions Starter monthly Starter annual at $99/year Pro checkout Stripe webhooks payment failed / succeeded handling reverse trial setup trial downgrade monthly revision reset STRIPE_STARTER_PRICE_ID=... STRIPE_STARTER_ANNUAL_PRICE_ID=... STRIPE_PRO_PRICE_ID=... Checkout now uses embedded Stripe Elements with PaymentElement , ExpressCheckoutElement , wallet buttons when available, and an Onara checkout page. account and limits I added plan display, trial days left, usage stats, upgrade CTAs, Starter / Pro cards, and annual Starter. Free -> 1 active site Starter -> 1 active site Pro / Trial -> 3 active sites Limits are checked before generation and enforced in Supabase. cancellation flow When Stripe sends customer.subscription.deleted or invoice.payment_failed , Onara now: updates the account sets show_url=false deploys a Cloudflare placeholder marks projects as suspended keeps Supabase records and GitHub backups cancel -> hide URL -> placeholder -> suspended project Cancellation hides the site but does not delete the generated code. what changed from devlog 001 Now the pipeline runs, agents generate sites, previews stream status, sites deploy, code backs up, projects persist, revisions work, billing is wired, trials downgrade, limits are enforced, and canceled sites get suspended. still missing lead SMS Pro code download weekly Google Reviews badge refresh monitoring privacy / terms cleanup support / consent copy launch outreach assets"}, {"post_id": 8868, "ts": "2026-06-14T19:21:29Z", "hours": 8.4192, "text": "devlog 001 - i started making the app Date: 2026-06-14 This update was big because Onara is not just plans anymore. I added real app code inside Onara_Code . Before this, it was mostly wiki pages, task lists, and design references. Now it has a real frontend and Supabase setup. what I built Next.js app landing page auth pages dashboard business build flow Google Places search agent progress screen Supabase migrations Supabase edge functions The app now has login, signup, password reset, protected dashboard routes, a contractor landing page, and a 4-step build flow: Find -> Confirm -> Style -> Generate I also added the mock agent progress screen. It shows the 10 agents running, streams progress, updates a preview, and has a fake retry moment. It is not the real backend yet, but it makes the frontend flow feel real. Supabase now has migrations for users, projects, pipeline jobs, revisions, RLS, auth triggers, and cron jobs. I also added edge functions for trial downgrade, revision reset, and Stripe webhook handling. what is still missing The big missing thing is: Onara_Code/pipeline/ That is where the FastAPI server needs to go. Still needed: FastAPI app /generate endpoint /health endpoint real agents AI client RAG deployment code account/billing pages Stripe checkout route verification I tried: npm run type-check but it failed because dependencies are not installed: tsc: not found next Next step: Build the FastAPI server. That is what turns the fake agent progress flow into the real Onara AI pipeline."}]...
|
Title: Onara by @aarushk | Stardance
Devlogs:
dev Title: Onara by @aarushk | Stardance
Devlogs:
devlog 001 - i started making the app Date: 2026-06-14 This update was big because Onara is not just plans anymore. I added real app code inside Onara_Code . Before this, it was mostly wiki pages, task lists, and design references. Now it has a real frontend and Supabase setup. what I built Next.js app landing page auth pages dashboard business build flow Google Places search agent progress screen Supabase migrations Supabase edge functions The app now has login, signup, password reset, protected dashboard routes, a contractor landing page, and a 4-step build flow: Find -> Confirm -> Style -> Generate I also added the mock agent progress screen. It shows the 10 agents running, streams progress, updates a preview, and has a fake retry moment. It is not the real backend yet, but it makes the frontend flow feel real. Supabase now has migrations for users, projects, pipeline jobs, revisions, RLS, auth triggers, and cron jobs. I also added edge functions for trial downgrade, revision reset, and Stripe webhook handling. what is still missing The big missing thing is: Onara_Code/pipeline/ That is where the FastAPI server needs to go. Still needed: FastAPI app /generate endpoint /health endpoint real agents AI client RAG deployment code account/billing pages Stripe checkout route verification I tried: npm run type-check but it failed because dependencies are not installed: tsc: not found next Next step: Build the FastAPI server. That is what turns the fake agent progress flow into the real Onara AI pipeline.
devlog 002 - the fake flow became the real app Date: 2026-06-18 Sorry abt not posting a devlog in a while, completely forgot i had to do them! (too locked in lol). Onara moved from prototype to real product system. Devlog 001 ended with the app shell, Supabase setup, and mock agent progress. Since then, the missing backend got built: FastAPI, real agents, deployment, revisions, billing, and account gating. Find -> Confirm -> Style -> Generate now connects to the actual pipeline. what I built FastAPI backend /generate and /health job queue + dedupe SSE progress stream dashboard build resume Cloudflare Tunnel + PM2 Next.js -> FastAPI -> agents -> Cloudflare -> Supabase AI pipeline I added the real 10-agent flow: Analyst, Content Writer, Style Agent, Planner, Prompt Engineer, Code Generator, Debugger, SEO Agent, QA, and Mobile check. Agent 6 now has a plan-gated model picker. Free -> Onara default Starter -> Copilot options Trial / Pro -> full access I also added shared AI clients for NVIDIA NIM, Ollama, and GitHub Copilot SDK. z-ai/glm-5.1 -> llama-4-maverick -> gemma4:e4b RAG and deployment I added RAG with ChromaDB, BM25 search, seeded HTML/CSS/JS patterns, and contractor layout examples. Deployment now does this: parse generated HTML split component files back up code to GitHub deploy to Cloudflare Pages save metadata in Supabase generated site -> GitHub -> Cloudflare -> Supabase revisions The revision page became a real workflow with: revision threads queued work log auto-pick or manual components changed-file summaries rollback UI retry without charging failed builds { instruction : " make the hero CTA bigger " , componentSelection : { mode : " auto " } } The UI also got cleaner: denser chat, better work log placement, flatter composer, and Onara styling. billing I added real billing: Stripe checkout sessions Starter monthly Starter annual at $99/year Pro checkout Stripe webhooks payment failed / succeeded handling reverse trial setup trial downgrade monthly revision reset STRIPE_STARTER_PRICE_ID=... STRIPE_STARTER_ANNUAL_PRICE_ID=... STRIPE_PRO_PRICE_ID=... Checkout now uses embedded Stripe Elements with PaymentElement , ExpressCheckoutElement , wallet buttons when available, and an Onara checkout page. account and limits I added plan display, trial days left, usage stats, upgrade CTAs, Starter / Pro cards, and annual Starter. Free -> 1 active site Starter -> 1 active site Pro / Trial -> 3 active sites Limits are checked before generation and enforced in Supabase. cancellation flow When Stripe sends customer.subscription.deleted or invoice.payment_failed , Onara now: updates the account sets show_url=false deploys a Cloudflare placeholder marks projects as suspended keeps Supabase records and GitHub backups cancel -> hide URL -> placeholder -> suspended project Cancellation hides the site but does not delete the generated code. what changed from devlog 001 Now the pipeline runs, agents generate sites, previews stream status, sites deploy, code backs up, projects persist, revisions work, billing is wired, trials downgrade, limits are enforced, and canceled sites get suspended. still missing lead SMS Pro code download weekly Google Reviews badge refresh monitoring privacy / terms cleanup support / consent copy launch outreach assets
devlog 003 - making Onara launch-ready Date: 2026-06-19 Since devlog 002, I mostly worked on turning Onara from “it works” into something closer to launch-ready. what I worked on billing + accounts I added more real account controls: cancel subscription from billing plan limits better account page better checkout layout Google-login warning if someone tries password login on a Google account Google account -> use Continue with Google Password account -> normal email/password login generated sites I worked on making the sites Onara creates more useful after launch: contact form lead emails better email HTML Pro code download cancellation placeholder pages Google Reviews refresh job support email surfaces contact form -> Onara lead email -> site owner inbox pipeline fixes I fixed more backend/build issues: longer pipeline timeout better health monitor support fixed /health HEAD checks fixed broken generated HTML cases improved Google Maps region filtering back toward DC / VA GET /health -> 200 OK HEAD /health -> 200 OK launch cleanup I added launch stuff that real products need: privacy policy terms of service support page favicon/logo polish SEO metadata .env.example updates docs for production fixes AI + training data I also added the start of a cleaner AI improvement system: user consent copy opt-out/delete handling training example storage QA-approved examples only no saving random bad generated sites into RAG good QA result -> redact -> save as training example bad result -> do not save biggest change Onara is not just generating sites now. It is starting to act like a real app with billing, support, cancellation, reviews, contact leads, account limits, and safer AI improvement rules. still left finish production deploy polish make generated site quality more consistent keep fixing slow render/build issues launch testing outreach assets
Trying to make the pipeline generate a proper output. Polishing up the application.
turning onara into Google Business Profile → website → quote form → missed-call recovery → lead inbox → booked job follow-up
First generated site!!! Pipeline finally works!
Ships:
I made Onara, an AI website builder for local businesses. It helps contractors turn their Google Business Profile, or manually entered business info, into a live website with copy, design, SEO, photos, contact forms, and a public URL. The hardest part was connecting everything together: the Next.js app, Supabase auth/database, Stripe billing, the FastAPI AI pipeline, Cloudflare deployment, GitHub backups, and the revision system. Getting the AI output to be good and not broken was also challenging. I’m proud that it is not just a mockup anymore. Users can sign in, search or enter a business, generate a site, revise it, manage billing, and keep their generated code backed up. To test it, sign up, search for a local business, confirm the details, pick a style, and start a build. After the site generates, try the revision page and ask for a small change like “make the hero CTA bigger.”...
|
1792990499.733223
|
1793076899.733223
|
|
2006
|
Flob (a platformer) by @potheterr | Stardance
|
potheterr
|
2
|
103.68
|
1489
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-03T13:26:56Z", "hours": 53.0, "multiplier": 17.22, "payout": 912, "blessing": "neutral", "text": "Welcome to FLOB 0.2.0.0!! This is the second of three updates I’d like to get out before the end of Stardance which will more than likely be the last update. This ship, I focused a lot on making new systems and expanding on old ones, all giving me unique challenges. I’m not the proudest of how the code turned out, but everything works for the most part so I will take it and run. I’ve also added a little tiny bit of a story that will be continued through my other projects I make in the future, which I am very excited for. Overall, this update was extremely fun to work on and I’m so happy with the way it turned out. That being said, the macOS and Linux builds of the game are UNTESTED, so if there are any huge issues find some way to let me know ASAP. Enjoy!", "repo": "https://github.com/JamesCorradinoGit/flowFreePlatformer", "demo": "https://potheterr.itch.io/flob"}, {"ship_num": 2, "ts": "2026-07-13T03:52:13Z", "hours": 50.0, "multiplier": 11.46, "payout": 577, "blessing": "neutral", "text": "This is a DEMO VERSION of my first published game, Flob! There are so many edge cases and bugs that I need to fix which is by far going to be the hardest part of this challenge, but I’m ready for it. Hopefully you all enjoy! (A video of the game is attached on the itch page).", "repo": "https://github.com/JamesCorradinoGit/flowFreePlatformer", "demo": "https://potheterr.itch.io/flob"}]...
|
[{"post_id": 45742, "ts": "202 [{"post_id": 45742, "ts": "2026-08-12T13:04:25Z", "hours": 0.6797, "text": "Hey everyone! Just reporting that I’ve been really burnt out with the game and I think I might call it here. I’ll probably return to it in future but as of right now I think it’s in a solid enough state. Thank you all!"}, {"post_id": 39756, "ts": "2026-08-02T22:33:00Z", "hours": 6.1347, "text": "Hello everyone! I’ve been much more focused on music and sounds over the last 2-3 days and I’m confident that there’s enough new content for a new ship. As for future content, I think 2 more worlds will be enough to round out the game. See y’all whenever I ship the update!"}, {"post_id": 37981, "ts": "2026-07-31T02:25:03Z", "hours": 8.7875, "text": "Hello everyone! Over the last two days, I’ve been working on new levels and many more features. My current issue is that I have a major logic issue with the moving platforms that I’m going to try to spend tomorrow fixing. See y’all soon!"}, {"post_id": 36561, "ts": "2026-07-28T19:13:31Z", "hours": 8.85, "text": "Hello everyone! Over the last couple of days I’ve been implementing some pretty cool light related stuff. I’ve also recoded many of the button systems and interactions with them because my coding of the systems originally were not my proudest work. (Pretty exciting stuff) In other news: I would like to reiterate that none of my work on this project or its related stuff (devlogs, READMEs, etc.) has been assisted with AI. I do not believe that the technology is fit for a majority of creative spaces and the day I use generative AI on one of my projects is long past the day I die. Until next time!"}, {"post_id": 34925, "ts": "2026-07-26T01:12:23Z", "hours": 4.9117, "text": "Hello again everyone! Over the last couple of days, I’ve been focusing on finishing up world 1 levels and doing lots and lots of general polish. However, now I am at an impasse. I need your help! If you’ve been following the project or are just passing by, please give your answer! Should I ship the new update as is and continue to ship small updates, or should I add another world or two and have a huge major ship? See y’all around!"}, {"post_id": 33861, "ts": "2026-07-24T03:51:47Z", "hours": 8.0322, "text": "Hello everyone! Lots more work has been done and I’m very very happy with the way things have been going, especially with reworking the tutorial text / instructions (which were mainly done in an hour on original release). Check out the video below for some tutorial revamp goodies. In other news: Flob is officially a super star project!!! This was so unexpected and I am so very honored to receive the super star award! There are so many other phenomenal projects that I personally believe deserve it way more than I do, but despite that I am so eternally grateful that I’ve made something people enjoy and are looking forward to full release of. See y’all again soon!"}, {"post_id": 32036, "ts": "2026-07-20T22:19:45Z", "hours": 8.0317, "text": "Hello everyone! I wasn’t expecting another devlog so soon, but here we are! I’ve had an obnoxious amount of free time so instead of doing real important stuff I’m going back and updating some UI to make it not look as “rushed”. Hopefully after I’m done with the slog that is user interface, I can return to gameplay!"}, {"post_id": 30683, "ts": "2026-07-18T13:47:51Z", "hours": 8.2372, "text": "It has been a long, long week for me over at Flob Inc. The 13th is when I got my wisdom teeth removed, so I got lots of time to reflect on my project so far. Speaking of which, Thank you everyone for the feedback after demo ship #1! It was so awesome seeing lots of good stuff to keep in mind for future updates along with my future projects. For now, here’s a glance at one of the new levels! See y’all soon!"}, {"post_id": 27498, "ts": "2026-07-13T03:38:28Z", "hours": 3.0597, "text": "Everything is complete…"}, {"post_id": 26171, "ts": "2026-07-10T20:21:24Z", "hours": 5.6414, "text": "For the last three or so days, I’ve been in audio burnout hell which reminds me that I am not cut out to be a sound engineer. That being said, the demo now has (mostly all) sound effects and I just need to make 2 more music tracks! After the release of the demo, I’ll most likely get the help of someone who knows what their doing, but for right now I say it passes. Expect a ship soon!"}, {"post_id": 24226, "ts": "2026-07-07T17:26:34Z", "hours": 6.4161, "text": "Ever since I almost ruined my project twice, I’ve started to work on lots and lots of polishing for my game! I’ll show off more whenever I have more finished, but for now take a look at this pseudo-screensaver I made (which is surprisingly performant) See y’all soon!"}, {"post_id": 21836, "ts": "2026-07-03T23:37:48Z", "hours": 0.6083, "text": "Logging again to make sure I’m not fully messing everything up. Had to rollback everything AGAIN because I am a stupid silly human being (my day is going phenomenally)"}, {"post_id": 21732, "ts": "2026-07-03T20:30:02Z", "hours": 3.9531, "text": "Today I almost ruined my entire project!! I accidentally deleted something that I thought was a leftover placeholder but it turns out it was the lynchpin holding my entire project together (which is funny because I only use it in one place pictured below) but all has been saved thanks to version control! Logging my time now just in case this breaks the godot plugin :P"}, {"post_id": 19579, "ts": "2026-06-30T22:28:47Z", "hours": 6.3931, "text": "Finally a devlog where I have interesting things to share! Over the last three or four days, I’ve highkey lowkey been doing way too much work with UI. Here is a cursory look at what I’ve done so far. A lot of the project is still unfinished (such as the options button doing nothing right now), but I’m happy I set up this baseline for myself. Almost everything when it comes to level selection, creation, and potential future additions are completely modular which means my life will be significantly easier as I wrap up this DEMO of the game. I will also be going back and edit my past devlogs to better represent what I’ve actually been up to rather than some terse statements!! See you soon!"}, {"post_id": 15905, "ts": "2026-06-25T21:00:53Z", "hours": 8.8308, "text": "It’s been more than a week…….. I loveee ui so so much…… For real though, I’ve been spending a lot of time on the UI of the game and how the general menu feel is. Everything shown is a prototype and is destined to change."}, {"post_id": 10035, "ts": "2026-06-16T16:25:49Z", "hours": 3.5228, "text": "There’s been no actual devlog updates for a week because I’ve been making the main menu music for the game! Yes, I know it is very early in the process to be worrying about the sound of the game, but I needed a break from coding and building so as to not get burnt out; however, now that the music is done I will get back to the coding magic!!"}, {"post_id": 5723, "ts": "2026-06-09T16:55:10Z", "hours": 4.7789, "text": "Over the last week, I feel as though I’ve figured out the main systems to get them in a position good enough to start real level design. The circle on the left is the way the PLAYER NODE completes their half of the whole level, with the other half being the puzzle solving with grids. This current first level contains no grids as it is a way to warm the player up to the movement of the game, but the rest of the game will almost always contain a grid puzzle that needs to be completed."}, {"post_id": 2294, "ts": "2026-06-04T18:16:27Z", "hours": 1.0494, "text": "Core update!! Core update!! Grids can be completed now! The grid system now has lots of customizability as there is the potential of custom grid edges (they’re all currently walls, but the possibilities are nearly endless) along with the interior of grid spaces, which are currently being used to spawn the line nodes and receivers which the player can interact with."}, {"post_id": 2101, "ts": "2026-06-04T13:04:51Z", "hours": 1.1253, "text": "Hello again again!! I’ve slightly updated the player movement so it is not as static as the default Godot player movement defaults. The movement still needs an immense amount of polish as I want to add variable jump heights, a proper state machine, and lots and lots of customizability in terms of how the player functions. Now that I have a working prototype of movement, I will focus on level creation and finishing up grid systems."}, {"post_id": 1196, "ts": "2026-06-03T01:37:36Z", "hours": 1.3769, "text": "I have returned with amazing news of modularity. A majority of actual grid work is done! This current rendition of the grids are fully modular in that you can adjust the X size and Y size to form a rectangular grid. Time for not default player control!"}, {"post_id": 984, "ts": "2026-06-02T19:22:12Z", "hours": 1.8433, "text": "Hello again! Good news, grid snapping works!! This means that one of the fundamental halves of the game is now fairly operational minus a few edge cases (that I am aware of). Next step is immediate grid fixes and the ability to actually detect a solved grid."}, {"post_id": 574, "ts": "2026-06-02T02:09:06Z", "hours": 1.7192, "text": "First one of these! Game progress is going fairly well (granted I basically just started outside of a line system I had made a week prior) as I just started making many of the core systems not be held together with duct tape and spaghetti."}]...
|
Title: Flob (a platformer) by @potheterr | Stardan Title: Flob (a platformer) by @potheterr | Stardance
Devlogs:
First one of these! Game progress is going fairly well (granted I basically just started outside of a line system I had made a week prior) as I just started making many of the core systems not be held together with duct tape and spaghetti.
Hello again! Good news, grid snapping works!! This means that one of the fundamental halves of the game is now fairly operational minus a few edge cases (that I am aware of). Next step is immediate grid fixes and the ability to actually detect a solved grid.
I have returned with amazing news of modularity. A majority of actual grid work is done! This current rendition of the grids are fully modular in that you can adjust the X size and Y size to form a rectangular grid. Time for not default player control!
Hello again again!! I’ve slightly updated the player movement so it is not as static as the default Godot player movement defaults. The movement still needs an immense amount of polish as I want to add variable jump heights, a proper state machine, and lots and lots of customizability in terms of how the player functions. Now that I have a working prototype of movement, I will focus on level creation and finishing up grid systems.
Core update!! Core update!! Grids can be completed now! The grid system now has lots of customizability as there is the potential of custom grid edges (they’re all currently walls, but the possibilities are nearly endless) along with the interior of grid spaces, which are currently being used to spawn the line nodes and receivers which the player can interact with.
Over the last week, I feel as though I’ve figured out the main systems to get them in a position good enough to start real level design. The circle on the left is the way the PLAYER NODE completes their half of the whole level, with the other half being the puzzle solving with grids. This current first level contains no grids as it is a way to warm the player up to the movement of the game, but the rest of the game will almost always contain a grid puzzle that needs to be completed.
There’s been no actual devlog updates for a week because I’ve been making the main menu music for the game! Yes, I know it is very early in the process to be worrying about the sound of the game, but I needed a break from coding and building so as to not get burnt out; however, now that the music is done I will get back to the coding magic!!
It’s been more than a week…….. I loveee ui so so much…… For real though, I’ve been spending a lot of time on the UI of the game and how the general menu feel is. Everything shown is a prototype and is destined to change.
Finally a devlog where I have interesting things to share! Over the last three or four days, I’ve highkey lowkey been doing way too much work with UI. Here is a cursory look at what I’ve done so far. A lot of the project is still unfinished (such as the options button doing nothing right now), but I’m happy I set up this baseline for myself. Almost everything when it comes to level selection, creation, and potential future additions are completely modular which means my life will be significantly easier as I wrap up this DEMO of the game. I will also be going back and edit my past devlogs to better represent what I’ve actually been up to rather than some terse statements!! See you soon!
Today I almost ruined my entire project!! I accidentally deleted something that I thought was a leftover placeholder but it turns out it was the lynchpin holding my entire project together (which is funny because I only use it in one place pictured below) but all has been saved thanks to version control! Logging my time now just in case this breaks the godot plugin :P
Logging again to make sure I’m not fully messing everything up. Had to rollback everything AGAIN because I am a stupid silly human being (my day is going phenomenally)
Ever since I almost ruined my project twice, I’ve started to work on lots and lots of polishing for my game! I’ll show off more whenever I have more finished, but for now take a look at this pseudo-screensaver I made (which is surprisingly performant) See y’all soon!
For the last three or so days, I’ve been in audio burnout hell which reminds me that I am not cut out to be a sound engineer. That being said, the demo now has (mostly all) sound effects and I just need to make 2 more music tracks! After the release of the demo, I’ll most likely get the help of someone who knows what their doing, but for right now I say it passes. Expect a ship soon!
Everything is complete…
It has been a long, long week for me over at Flob Inc. The 13th is when I got my wisdom teeth removed, so I got lots of time to reflect on my project so far. Speaking of which, Thank you everyone for the feedback after demo ship #1! It was so awesome seeing lots of good stuff to keep in mind for future updates along with my future projects. For now, here’s a glance at one of the new levels! See y’all soon!
Hello everyone! I wasn’t expecting another devlog so soon, but here we are! I’ve had an obnoxious amount of free time so instead of doing real important stuff I’m going back and updating some UI to make it not look as “rushed”. Hopefully after I’m done with the slog that is user interface, I can return to gameplay!
Hello everyone! Lots more work has been done and I’m very very happy with the way things have been going, especially with reworking the tutorial text / instructions (which were mainly done in an hour on original release). Check out the video below for some tutorial revamp goodies. In other news: Flob is officially a super star project!!! This was so unexpected and I am so very honored to receive the super star award! There are so many other phenomenal projects that I personally believe deserve it way more than I do, but despite that I am so eternally grateful that I’ve made something people enjoy and are looking forward to full release of. See y’all again soon!
Hello again everyone! Over the last couple of days, I’ve been focusing on finishing up world 1 levels and doing lots and lots of general polish. However, now I am at an impasse. I need your help! If you’ve been following the project or are just passing by, please give your answer! Should I ship the new update as is and continue to ship small updates, or should I add another world or two and have a huge major ship? See y’all around!
Hello everyone! Over the last couple of days I’ve been implementing some pretty cool light related stuff. I’ve also recoded many of the button systems and interactions with them because my coding of the systems originally were not my proudest work. (Pretty exciting stuff) In other news: I would like to reiterate that none of my work on this project or its related stuff (devlogs, READMEs, etc.) has been assisted with AI. I do not believe that the technology is fit for a majority of creative spaces and the day I use generative AI on one of my projects is long past the day I die. Until next time!
Hello everyone! Over the last two days, I’ve been working on new levels and many more features. My current issue is that I have a major logic issue with the moving platforms that I’m going to try to spend tomorrow fixing. See y’all soon!
Hello everyone! I’ve been much more focused on music and sounds over the last 2-3 days and I’m confident that there’s enough new content for a new ship. As for future content, I think 2 more worlds will be enough to round out the game. See y’all whenever I ship the update!
Hey everyone! Just reporting that I’ve been really burnt out with the game and I think I might call it here. I’ll probably return to it in future but as of right now I think it’s in a solid enough state. Thank you all!
Ships:
This is a DEMO VERSION of my first published game, Flob! There are so many edge cases and bugs that I need to fix which is by far going to be the hardest part of this challenge, but I’m ready for it. Hopefully you all enjoy! (A video of the game is attached on the itch page).
Welcome to FLOB 0.2.0.0!! This is the second of three updates I’d like to get out before the end of Stardance which will more than likely be the last update. This ship, I focused a lot on making new systems and expanding on old ones, all giving me unique challenges. I’m not the proudest of how the code turned out, but everything works for the most part so I will take it and run. I’ve also added a little tiny bit of a story that will be continued through my other projects I make in the future, which I am very excited for. Overall, this update was extremely fun to work on and I’m so happy with the way it turned out. That being said, the macOS and Linux builds of the game are UNTESTED, so if there are any huge issues find some way to let me know ASAP. Enjoy!...
|
1792994066.750957
|
1793080466.750957
|
|
37328
|
Untitled by @kingjamesh | Stardance
|
kingjamesh
|
0
|
103.56
|
0
|
[]
|
[{"post_id": 65909, "ts": "202 [{"post_id": 65909, "ts": "2026-09-11T11:19:07Z", "hours": 1.4806, "text": "6.7b 🤪🤪🤪"}, {"post_id": 65629, "ts": "2026-09-10T21:37:28Z", "hours": 102.08, "text": "6th longest devlog! for gits and shiggles"}]...
|
Title: Untitled by @kingjamesh | Stardance
Devlog Title: Untitled by @kingjamesh | Stardance
Devlogs:
6th longest devlog! for gits and shiggles
6.7b 🤪🤪🤪...
|
1792939957.6564832
|
1793803957.6564832
|
|
42754
|
STREAMLINE by @Rishabh_mewada | Stardance
|
Rishabh_mewada
|
0
|
103.06
|
0
|
[]
|
[{"post_id": 74808, "ts": "202 [{"post_id": 74808, "ts": "2026-09-28T10:05:10Z", "hours": 9.5169, "text": "Body & frame In this time period the overall assembly of the frame and body and the mechanisms which will hold all the body together and will last all most 2G’s during flight and make sure that nothing get dismantled at 300km/h (unlike Boeing) and also make sure that the frame is tough enough to withstand high tension and gravitational forces and not snap under it and also making sure that everything can fit properly with leaving some room for some wiggle and in this process i had to change the battery that i aimed to use, to fit it inside drone and made a decision to not remake the drone itself again that’s all folks! can’t belive that this is my shortest devlog , geez i need to work more efficiently…. Tools used -fusion 360"}, {"post_id": 65988, "ts": "2026-09-11T14:31:05Z", "hours": 9.7989, "text": "Main body design So the wing is now designed from the NACA 0016 airfoil but there one problem , how do we know that we are getting the require drag and lift ?? , the answer is simple just put your airfoil model into simscale and use C(D) vs C(L) graph from your cfd post process result , okay now we have our data after 10 Mins of simulation , but oh its is newtons… now we will use the equation that every engineers use this formula Force(Newtons) = C(D) * 1/2 * p * V^2 * A Notations C(D) = coefficient of drag p = density of air V = velocity -A = area so after some mind soaring calculations you get 24.82 Grams of drag per wing yeppe , congratulations ! you have successfully got a low drag and zero lift wing !! apart from all of this accurate and precise modeling is done for low error model , just joining the wings to the core testing a locking mechanism making few adjustments in models and making the model aerodynamic that’s it for this devlog folks nothing more ! sources used : Simscale - CFD - Incompressible , V : 88.3 m/s"}, {"post_id": 62886, "ts": "2026-09-06T12:38:47Z", "hours": 12.19, "text": "New mounting & aero designs Well i looked at some designs of the worlds fastest fpv pod drone from youtube of world record holders in search of proper tested ideas and mounting hole positioning this helps in saving time and money while the design of the drones is not copied the core idea and the mistakes of the record holders drones are kept in mind to avoid any costly mistakes , while this method cant guarantee 100% perfection of the entire assembely or the design there can always be room for mistakes despite trying to avoid it Now for the new elements the issue with the PDB mounting holes have bought me to a conclusion to change the distance between the mounting holes and match it to the FC so a single big hole can be used for all purpose avoiding any poor mounting or adding additional weight just to support any additional unnecessary supports for the holes talking about supports the supports between the holes and the walls are now webbed with thickness of 1mm with multiple walls to make it stiff enough for high G forces , making it a better design choice for mounting and stiffness about the new addition the previous design of the wing is now changed to a proper NACA airfoil to avoid excess drag and no lift to avoid instability at high speed during maneuvering Details : Videos taken inspiration from https://youtu.be/-Iu6k9qJQ4I https://youtu.be/RoSSaSkOTTc -Airfoil details attached in images -Website - http://www.windandwet.com/windturbine/airfoil_plotter/index.php"}, {"post_id": 50304, "ts": "2026-08-19T13:51:06Z", "hours": 9.5639, "text": "Components placements , Frame & CFD for the new Drone design the placements and the frame of the components matters a lot because its helps in reducing weight and keeping it balanced through constant speed and also not concentrate all the weight on a specific point (weight distribution), to model the frame correctly i needed to be sure that the prototype Aerodynamics are correct and balanced without causing to much drag on the cone and on the wings thanks to the water droplet body and the aerofoil wings the drag was significantly less and the main points causing the drag where the points at which the air and the body would first impact and the drag caused by it was mostly negligible allowing the drone to fly at its true capacity rather than being a literal flying brick Software used fusion 360 (modeling/CAD) Simscale (CFD analysis , Incompressible fluid (air) ) Reading used speed / velocity inlet - 83.33m/s pressure outlet - 0 / constant walls of the simulation box , Slip walls settings used"}, {"post_id": 45804, "ts": "2026-08-12T14:52:25Z", "hours": 10.1839, "text": "New concept for streamline! - Due to my new simulation of the drone flaring and doing some analysis i found out that the flaring provides little to no aerodynamic advantage and instead adds up more weight to the drone , simply said the new analysis showed that a classic fpv drone wont bring up the aerodynamic advantage i am looking for instead a pod drone with a uni-body with integrated chassis would be better for speed and aerodynamics i used NASA Airfoil sim to simulate the NACA wing profile And applied specific Camber angles (0.3 Degrees) which almost eliminates most of the drag on the wing while the current stage of the drone in prototype and mockups Software’s / services used Fusion 360 Simscale NASA Airfoil Sim (student) Airfoil plotter Airfoil DAT to Spline ( or any other fusion 360 Plugin for the conversion of CSV file to spline for accurate Airfoil Profile) Although i wasted a ton of time on the classic but atleast i got to learn more complex modeling such as T-spline and Surface modeling for such surfaces . I am currently not using ansys because using ansys for small task is a waste of time and also my ansys is kind of having a crack down idk why"}, {"post_id": 38916, "ts": "2026-08-01T14:40:33Z", "hours": 51.8014, "text": "PDB , Chassis & Flaring"}]...
|
Title: STREAMLINE by @Rishabh_mewada | Stardance
Title: STREAMLINE by @Rishabh_mewada | Stardance
Devlogs:
PDB , Chassis & Flaring
New concept for streamline! - Due to my new simulation of the drone flaring and doing some analysis i found out that the flaring provides little to no aerodynamic advantage and instead adds up more weight to the drone , simply said the new analysis showed that a classic fpv drone wont bring up the aerodynamic advantage i am looking for instead a pod drone with a uni-body with integrated chassis would be better for speed and aerodynamics i used NASA Airfoil sim to simulate the NACA wing profile And applied specific Camber angles (0.3 Degrees) which almost eliminates most of the drag on the wing while the current stage of the drone in prototype and mockups Software’s / services used Fusion 360 Simscale NASA Airfoil Sim (student) Airfoil plotter Airfoil DAT to Spline ( or any other fusion 360 Plugin for the conversion of CSV file to spline for accurate Airfoil Profile) Although i wasted a ton of time on the classic but atleast i got to learn more complex modeling such as T-spline and Surface modeling for such surfaces . I am currently not using ansys because using ansys for small task is a waste of time and also my ansys is kind of having a crack down idk why
Components placements , Frame & CFD for the new Drone design the placements and the frame of the components matters a lot because its helps in reducing weight and keeping it balanced through constant speed and also not concentrate all the weight on a specific point (weight distribution), to model the frame correctly i needed to be sure that the prototype Aerodynamics are correct and balanced without causing to much drag on the cone and on the wings thanks to the water droplet body and the aerofoil wings the drag was significantly less and the main points causing the drag where the points at which the air and the body would first impact and the drag caused by it was mostly negligible allowing the drone to fly at its true capacity rather than being a literal flying brick Software used fusion 360 (modeling/CAD) Simscale (CFD analysis , Incompressible fluid (air) ) Reading used speed / velocity inlet - 83.33m/s pressure outlet - 0 / constant walls of the simulation box , Slip walls settings used
New mounting & aero designs Well i looked at some designs of the worlds fastest fpv pod drone from youtube of world record holders in search of proper tested ideas and mounting hole positioning this helps in saving time and money while the design of the drones is not copied the core idea and the mistakes of the record holders drones are kept in mind to avoid any costly mistakes , while this method cant guarantee 100% perfection of the entire assembely or the design there can always be room for mistakes despite trying to avoid it Now for the new elements the issue with the PDB mounting holes have bought me to a conclusion to change the distance between the mounting holes and match it to the FC so a single big hole can be used for all purpose avoiding any poor mounting or adding additional weight just to support any additional unnecessary supports for the holes talking about supports the supports between the holes and the walls are now webbed with thickness of 1mm with multiple walls to make it stiff enough for high G forces , making it a better design choice for mounting and stiffness about the new addition the previous design of the wing is now changed to a proper NACA airfoil to avoid excess drag and no lift to avoid instability at high speed during maneuvering Details : Videos taken inspiration from https://youtu.be/-Iu6k9qJQ4I https://youtu.be/RoSSaSkOTTc -Airfoil details attached in images -Website - http://www.windandwet.com/windturbine/airfoil_plotter/index.php
Main body design So the wing is now designed from the NACA 0016 airfoil but there one problem , how do we know that we are getting the require drag and lift ?? , the answer is simple just put your airfoil model into simscale and use C(D) vs C(L) graph from your cfd post process result , okay now we have our data after 10 Mins of simulation , but oh its is newtons… now we will use the equation that every engineers use this formula Force(Newtons) = C(D) * 1/2 * p * V^2 * A Notations C(D) = coefficient of drag p = density of air V = velocity -A = area so after some mind soaring calculations you get 24.82 Grams of drag per wing yeppe , congratulations ! you have successfully got a low drag and zero lift wing !! apart from all of this accurate and precise modeling is done for low error model , just joining the wings to the core testing a locking mechanism making few adjustments in models and making the model aerodynamic that’s it for this devlog folks nothing more ! sources used : Simscale - CFD - Incompressible , V : 88.3 m/s
Body & frame In this time period the overall assembly of the frame and body and the mechanisms which will hold all the body together and will last all most 2G’s during flight and make sure that nothing get dismantled at 300km/h (unlike Boeing) and also make sure that the frame is tough enough to withstand high tension and gravitational forces and not snap under it and also making sure that everything can fit properly with leaving some room for some wiggle and in this process i had to change the battery that i aimed to use, to fit it inside drone and made a decision to not remake the drone itself again that’s all folks! can’t belive that this is my shortest devlog , geez i need to work more efficiently…. Tools used -fusion 360...
|
1792522311.680547
|
1793127111.680547
|
|
700
|
Void Strike by @JudeW | Stardance
|
JudeW
|
1
|
103.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-26T15:27:38Z", "hours": 103.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Hi! The project I’ve been working on is called Void Strike. It’s a space shooter game in which the player controls a spaceship and must survive hordes of enemy waves. The reason why I chose to create this game is that I thought it would be easy. Since I’ve never really used Godot, I thought I should start simple. By the end of working on it, I can confidently say that I’ve learned at least the basics of the engine. That’s all anyway. Have Fun! Also, last night when I was trying to add it to Itch.io, I accidentally overwrote LITERALLY ALL of my files and everything, so the only thing I have left is the HTML export, and the entire project on my Godot account is just gone, and I can’t recover it, so if there is anything a little buggy, that’s probably why. And I can’t do anything about it, sorry. I just decided to ship it as it currently is instead of not shipping it at all, since I’ve already spent too much of my time on this. Once more, I’m sorry.", "repo": "https://github.com/judeweibley-cell/Void-Strike", "demo": "https://ludew.itch.io/void-strike"}]...
|
[{"post_id": 73757, "ts": "202 [{"post_id": 73757, "ts": "2026-09-25T21:24:54Z", "hours": 2.5992, "text": "Finally finished the game!!! Just posting a quick devlog before shipping. I added satellites and space junk that can fly in from the right side of your screen, which adds an extra obstacle. The only hard part about it was figuring out some physics equations with Newton’s Law of Universal Gravitation. After that, it was finished. Here’s my code if you want to look at it(GDScript): extends Node2D var item = 0 var active_node: Node2D = null var velocity := Vector2.ZERO var rotation_speed := 0.0 var spawning_enabled := true const MIN_SPAWN_TIME = 10.0 const MAX_SPAWN_TIME = 15.0 const PLANET_POSITION = Vector2(300, 1500) const GRAVITY_STRENGTH = 450000.0 @onready var timer = $Timer @onready var small_satellite = $“Small satelltite” @onready var large_satellite = $“Large satellite” @onready var scrap = $Scrap func _ready() -> void: randomize_next_spawn_time() func _process(delta: float) -> void: if active_node and active_node.visible: var vector_to_planet = PLANET_POSITION - active_node.global_position var distance = vector_to_planet.length() var direction = vector_to_planet.normalized() var gravity_force = direction * (GRAVITY_STRENGTH / (distance * distance)) velocity += gravity_force * delta active_node.global_position += velocity * delta active_node.rotation += rotation_speed * delta if active_node.global_position.x < -150: disable_active_node() func _on_timer_timeout() -> void: randomize_next_spawn_time() if not spawning_enabled: return item = randi_range(1, 3) if item == 1: pick_small() elif item == 2: pick_large() else: pick_scrap() func randomize_next_spawn_time() -> void: if timer: timer.wait_time = randf_range(MIN_SPAWN_TIME, MAX_SPAWN_TIME) timer.start() func reset_and_launch(node: Node2D): disable_active_node() small_satellite.hide() large_satellite.hide() scrap.hide() node.show() node.global_position = Vector2(600, randi_range(0, 960)) velocity = Vector2(-150, -45) rotation_speed = randf_range(-1.5, 1.5) if node.has_method(\"set_deferred\"): node.set_deferred(\"monitoring\", true) node.set_deferred(\"monitorable\", true) active_node = node func disable_active_node(): if active_node: active_node.hide() if active_node.has_method(“set_deferred”): active_node.set_deferred(“monitoring”, false) active_node.set_deferred(“monitorable”, false) func stop_spawning() -> void: spawning_enabled = false timer.stop() func start_spawning() -> void: spawning_enabled = true randomize_next_spawn_time() func pick_small(): reset_and_launch(small_satellite) func pick_large(): reset_and_launch(large_satellite) func pick_scrap(): reset_and_launch(scrap) func _on_scrap_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node() func _on_large_satellite_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node() func _on_small_satelltite_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node()"}, {"post_id": 73337, "ts": "2026-09-24T22:14:34Z", "hours": 10.0881, "text": "Lately I’ve just been polishing the game. Nothing super interesting. I fixed the keybindings because when you selected a key with a long name like RightBracket, the label would expand into the button and overlap. I just made a better layout for it and made it so the text would be aligned on the right side, making it expand to the left instead. Then I worked on cleaning up some of my code since I’m planning on shipping tomorrow. Then I added a TON of polish to the main menu. I added a little rotating tip at the bottom and displayed your high score and highest wave at the top of the menu, which was easy enough. I still want to log at least two more hours, so if anyone has ideas, please let me know, because I’m out of ideas. Also, in the pictures, if the text looks sideways, it’s because I rotated it as a little animation. I think the current total for lines of code is 3005, if you’re interested, btw."}, {"post_id": 67665, "ts": "2026-09-13T20:25:53Z", "hours": 5.2769, "text": "I’ve just been working on adding some finishing touches lately, most of which include working with the new log feature. Inside of it I have three different tabs Enemies which is just a list of all of the different enemies and their stats like hp and speed. The second one is for achievements. I have ten so far, which include: First Orbit, earned by playing for 15 mins. Deep Space Transit for 30 minutes, and Time Flies for an hour. Atmosphere Cleared for getting to wave 5. Flight Lieutenant for wave 15. Squadron Leader for wave 30, and Cosmic Anomaly for 50. Just Getting Warm for killing a thousand enemies. Determined I for dying 50 times and Determined II for dying 100 times. I also added some progress bars to visually show your progress towards the achievements. For the stats menu, all I changed was adding a darker panel behind all the stats to add some detail; other than that, that’s all I did. Also, the scrolling menus were almost my downfall."}, {"post_id": 66787, "ts": "2026-09-12T17:48:29Z", "hours": 3.1139, "text": "This morning, I’ve been working on adding a statistics menu to the menu, which keeps track of stuff like your highest wave or how many power-ups you’ve bought. All of the things are saved after closing the window, so not much has been added, but it’s something."}, {"post_id": 66317, "ts": "2026-09-12T02:32:23Z", "hours": 6.9156, "text": "Fairly large update!!! Over the past few days, I’ve been working and have gotten quite a lot done. Recent changes include A new bomber enemy who appears on wave 15, dropping bombs as it passes through. Bombs have 3 seconds before exploding and deal the standard 1 HP. Then I polished the menu so that instead of having ugly buttons down at the bottom of the screen, I now have large transparent buttons right in the middle of the screen. I also made the buttons feel really juicy, changing color and playing a short clicking sound when hovered over with the mouse. I changed up the settings panel by adding some darker panels for detail and organization. Instead of the set WASD and arrow keys, I now have key binding as an option. I don’t know what other controls players would use, but just in case, and it also makes the game feel more polished. I think right now I plan on adding a stats page in the menu next that can showcase stuff like your highest wave, how many attempts, and enemies killed. But I think I’m going to save that for tomorrow. So for now, I’ll see you in the next devlog. :)"}, {"post_id": 62492, "ts": "2026-09-05T21:34:48Z", "hours": 9.9294, "text": "🎉🎉Major Update🎉🎉 After a little bit of playtesting, I came to the conclusion that the game needed to be much harder because it came up as a problem more often than not. I was already planning to add a few more enemy types, so it didn’t really matter. New Enemy Types 1) A horde of diver enemies 2) A large tank enemy that has double shots 3) A Suicider enemy which pathfinds to the player 4) An asteroid field that can spawn I also plan on adding a bomber enemy with explosions, and a flame thrower enemy which will deal more damage the longer you are in the flames and will burn your fuel. But because I was so close to the 10-hour limit, I have to make a devlog before continuing on it. I also decreased the wavelength from 30 seconds to just 20 because it made for a much faster-paced game and was easier on the player. In the future, I plan on adding a keybind option to the settings, which might take a while to figure out, bosses, which probably won’t happen, and a ton more polish to the menu because it looks terrible."}, {"post_id": 57756, "ts": "2026-08-30T01:10:30Z", "hours": 0.6822, "text": "Small Update: I just added a notes and acknowledgements page to replace the old broken leaderboard page. It just includes some writing and a link to my new Discord Page. If you want to join early to the launch, here’s the link: https://discord.gg/ccgyRZArYm"}, {"post_id": 57724, "ts": "2026-08-29T23:55:41Z", "hours": 8.8753, "text": "🎉🎉MAJOR UPDATE🎉🎉: For the past few days I’ve been working on a few updates, which include finishing and balancing the new Super Nova feature. When you max out all 3 power-up upgrades, it allows you to super charge. One of them includes Double Shot, 2x score on top of 2x score, and buffs for a short amount of time after your shield breaks. I made waves infinitely and made them progressively harder with each passing wave. I added a slight amount of polish to the menu where a little click sound plays when you toggle settings or press a button. I realized that when the player got hit it wasn’t very noticeable since it played the same sound as when an enemy got hit, so I added screen shake which was something I wanted to add for a while but procrastinated it because the way I made my scrolling background with a Parallax background that had a Parallax layer and sprite 2D as a child so when I added the camera 2D node it stopped the background from scrolling so I had to delete all of that and update it with the newer method. But after an hour or so, I got it looking clean and was happy with it, so now when the player takes damage, there is a very noticeable shake to the screen, which helps indicate that you got hit. I also added this to the enemy, but you have to build up a fairly large consecutive hit counter to really notice it. I did start to work on a new tank enemy since all of the existing ones are relatively weak, so this one will have 5 HP, which is half of an asteroid, and will shoot double-shot bullets, which will be punishing if the player gets hit by it. Speaking of HP, instead of healing the player’s hearts back to their maximum amount despite the current amount, it now only heals you by one heart. Now normally, I would have a video to showcase all of these new features, but my thing is weird and will only take images, not videos, so sorry if it’s missing, like all of the updates."}, {"post_id": 48557, "ts": "2026-08-17T00:20:01Z", "hours": 10.9817, "text": "Major Update: Over the past few days, I’ve added a lot of features that will have a significant impact on the game. The first of which is a new shop where the player can purchase upgrades, including a +5% speed increase (limit of 25%), a +5% fire rate upgrade (limit of 25%), and, lastly, a refuel upgrade, which will refill 5% for the cost of 1 coin. The player now has 3 lives instead of just 1, which will allow the player to progress through the game more. In the shop the player can upgrade the amount of lives they have(max of 5). After each wave their health returns to it’s maximum, but fuel will remain the same. In the power-ups tab, the player can increase the duration of each power-up by a maximum of 5 seconds. Once the player maxes out all 3 power-ups, they will unlock a feature called Super Nova were they can select one of the three power-ups to gain a new feature that will help the player survive new waves. Speaking of waves, the next change includes breaking up the game into multiple waves. This change allows the player to get a break between waves to upgrade their ship in the shop. This also makes the player feel like they are progressing through the game more."}, {"post_id": 45996, "ts": "2026-08-12T20:45:30Z", "hours": 5.9294, "text": "Large Update: Last night and this morning, I’ve been working on some new features, including a new fuel tank that slowly depletes, and the only way to refill it is by collecting fuel canisters. This change also allows the player to hold down Shift to get a 50% speed increase, but the fuel tank goes down twice as fast. I also added a new fire particle effect that follows the player, making the game feel much livelier. Coins are also a new feature that have a 10% drop rate on the death of an enemy. Right now, coins do nothing, but in the future I have plans to add a shop/upgrade feature. The player now has three lives instead of one; this makes the game feel more forgiving, but when you lose a heart, your fuel tank decreases by 20%, making fuel a much bigger problem than before. When your fuel tank hits 0, the game is over regardless of how many hearts the player has."}, {"post_id": 45420, "ts": "2026-08-11T21:06:05Z", "hours": 2.1111, "text": "Today’s changes include adding a new power-up, which is a shield that protects the player from one hit for 10 seconds. There is a shield Icon which follows the player around, acting as a visual indicator for the power-up. I also made the player movement much smoother by making the player accelerate in a direction instead of moving at a flat rate, which makes the game overall feel much more “alive”."}, {"post_id": 44986, "ts": "2026-08-11T03:37:37Z", "hours": 9.8844, "text": "Major update: as you can tell from me logging in more than 9 hours, I made a lot of changes, which include two new enemies because I realized as long as you don’t actively try to die, you can live forever, so we have two new enemies, both of which fire bullets at the player, so you have something that poses a threat unlike the old enemies. One is quick, has a fast firing speed, and is small, but only has 1 hp. It also provides more points than its much slower partner, who has 2 hp, a slower firing rate, and a bigger hitbox. I also added two power-ups, randomly selected from the two as collectable items: the first doubles your shoot cooldown for 5 seconds, and the second doubles your score income for 15 seconds. When you collect a power-up, a bar appears at the bottom of your screen, showing how much time remains on your power-up. That’s all that I did for this week, and more features are on their way. Thanks! p.s. I can’t add a video containing the update because my thing is weird and only lets me upload images to Stardance. Sorry about the inconvenience😭"}, {"post_id": 41458, "ts": "2026-08-05T17:55:55Z", "hours": 3.8344, "text": "These past few days, I worked on adding polish, bug fixes, and a new load screen. The load screen GUI is just a placeholder until I can polish it off. I might have to scrap an online leaderboard because I’m new to Godot and know very little GD script, so I can’t use SilentWolf. I’ve been working on implementing Talo, but I can’t find any tutorials, and Google can’t help me with it. Unless I can get it working I don’t think I can add an online leader board."}, {"post_id": 38325, "ts": "2026-07-31T17:27:19Z", "hours": 1.1819, "text": "I need help. I did finally fix the one bug that stopped enemies from spawning, but my next goal was to make a leaderboard, so I set up all of the UI for it, and when I realized I had no idea what I was doing, I ultimately looked up a YouTube tutorial. I didn’t realize that I needed to use a plugin to create an online server for my game. And when I tried to download Silent Wolf, it wouldn’t let me because I was still using version 4.4, and I didn’t want to update it in case it broke my game. So do I scrap leaderboards, or is there some other way?"}, {"post_id": 38211, "ts": "2026-07-31T14:41:42Z", "hours": 5.3556, "text": "Lately I’ve been working on adding a settings feature that includes options for music, sound effects, and a reset data button. While working on this feature, I managed to break my entire game, so fingers crossed I can fix it. I plan on adding an online leaderboard (If I can fix the game)."}, {"post_id": 35191, "ts": "2026-07-26T13:44:00Z", "hours": 4.8325, "text": "Void Strike is a space shooter-type game in which the player must test their skills by trying to survive for as long as possible while gaining points by killing enemies. Changelog: Added an asteroid, which is a new obstacle that has a lot of HP and permits the enemies to advance closer to the player. Bug fixes I haven’t posted a devlog because I’ve been on vacation so I’m very behind on my project."}, {"post_id": 3278, "ts": "2026-06-06T04:13:02Z", "hours": 6.4203, "text": "Void Strike is a space shooter-type game in which the player must test their skills by trying to survive for as long as possible while gaining points by killing enemies. I haven’t posted a Dev-log for a while, but I’ve added a lot of features in that time. Changelog Scrolling background and particle effects Sound effects On-screen score counter High-score Game over screen Player Balancing Difficulty increases over time My next steps will be to add a main menu, possibly a shop and a currency to buy player upgrades, and a competitive global scoreboard. P.S. I would take a video, but my internet keeps showing an error, so I’ve taken a photo instead. Believe me, I added what I said I did."}, {"post_id": 1829, "ts": "2026-06-04T01:27:56Z", "hours": 1.7686, "text": "Void Strike is a simple space shooter type game that I’m working on. I know it’s a little simple, but I’m inexperienced with Godot. Changelog You can hold down space to shoot 2 new enemies (1 fast, and 1 slow) Randomized enemy spawning"}, {"post_id": 1748, "ts": "2026-06-03T22:43:16Z", "hours": 2.7453, "text": "Void Strike, which is a space shooter I just started working on. It will be on the simpler side, because I’m new to using Godot. So far I have the player movement, and shooting working. I plan to add a lot more in the future."}]...
|
Title: Void Strike by @JudeW | Stardance
Devlogs: Title: Void Strike by @JudeW | Stardance
Devlogs:
Void Strike, which is a space shooter I just started working on. It will be on the simpler side, because I’m new to using Godot. So far I have the player movement, and shooting working. I plan to add a lot more in the future.
Void Strike is a simple space shooter type game that I’m working on. I know it’s a little simple, but I’m inexperienced with Godot. Changelog You can hold down space to shoot 2 new enemies (1 fast, and 1 slow) Randomized enemy spawning
Void Strike is a space shooter-type game in which the player must test their skills by trying to survive for as long as possible while gaining points by killing enemies. I haven’t posted a Dev-log for a while, but I’ve added a lot of features in that time. Changelog Scrolling background and particle effects Sound effects On-screen score counter High-score Game over screen Player Balancing Difficulty increases over time My next steps will be to add a main menu, possibly a shop and a currency to buy player upgrades, and a competitive global scoreboard. P.S. I would take a video, but my internet keeps showing an error, so I’ve taken a photo instead. Believe me, I added what I said I did.
Void Strike is a space shooter-type game in which the player must test their skills by trying to survive for as long as possible while gaining points by killing enemies. Changelog: Added an asteroid, which is a new obstacle that has a lot of HP and permits the enemies to advance closer to the player. Bug fixes I haven’t posted a devlog because I’ve been on vacation so I’m very behind on my project.
Lately I’ve been working on adding a settings feature that includes options for music, sound effects, and a reset data button. While working on this feature, I managed to break my entire game, so fingers crossed I can fix it. I plan on adding an online leaderboard (If I can fix the game).
I need help. I did finally fix the one bug that stopped enemies from spawning, but my next goal was to make a leaderboard, so I set up all of the UI for it, and when I realized I had no idea what I was doing, I ultimately looked up a YouTube tutorial. I didn’t realize that I needed to use a plugin to create an online server for my game. And when I tried to download Silent Wolf, it wouldn’t let me because I was still using version 4.4, and I didn’t want to update it in case it broke my game. So do I scrap leaderboards, or is there some other way?
These past few days, I worked on adding polish, bug fixes, and a new load screen. The load screen GUI is just a placeholder until I can polish it off. I might have to scrap an online leaderboard because I’m new to Godot and know very little GD script, so I can’t use SilentWolf. I’ve been working on implementing Talo, but I can’t find any tutorials, and Google can’t help me with it. Unless I can get it working I don’t think I can add an online leader board.
Major update: as you can tell from me logging in more than 9 hours, I made a lot of changes, which include two new enemies because I realized as long as you don’t actively try to die, you can live forever, so we have two new enemies, both of which fire bullets at the player, so you have something that poses a threat unlike the old enemies. One is quick, has a fast firing speed, and is small, but only has 1 hp. It also provides more points than its much slower partner, who has 2 hp, a slower firing rate, and a bigger hitbox. I also added two power-ups, randomly selected from the two as collectable items: the first doubles your shoot cooldown for 5 seconds, and the second doubles your score income for 15 seconds. When you collect a power-up, a bar appears at the bottom of your screen, showing how much time remains on your power-up. That’s all that I did for this week, and more features are on their way. Thanks! p.s. I can’t add a video containing the update because my thing is weird and only lets me upload images to Stardance. Sorry about the inconvenience😭
Today’s changes include adding a new power-up, which is a shield that protects the player from one hit for 10 seconds. There is a shield Icon which follows the player around, acting as a visual indicator for the power-up. I also made the player movement much smoother by making the player accelerate in a direction instead of moving at a flat rate, which makes the game overall feel much more “alive”.
Large Update: Last night and this morning, I’ve been working on some new features, including a new fuel tank that slowly depletes, and the only way to refill it is by collecting fuel canisters. This change also allows the player to hold down Shift to get a 50% speed increase, but the fuel tank goes down twice as fast. I also added a new fire particle effect that follows the player, making the game feel much livelier. Coins are also a new feature that have a 10% drop rate on the death of an enemy. Right now, coins do nothing, but in the future I have plans to add a shop/upgrade feature. The player now has three lives instead of one; this makes the game feel more forgiving, but when you lose a heart, your fuel tank decreases by 20%, making fuel a much bigger problem than before. When your fuel tank hits 0, the game is over regardless of how many hearts the player has.
Major Update: Over the past few days, I’ve added a lot of features that will have a significant impact on the game. The first of which is a new shop where the player can purchase upgrades, including a +5% speed increase (limit of 25%), a +5% fire rate upgrade (limit of 25%), and, lastly, a refuel upgrade, which will refill 5% for the cost of 1 coin. The player now has 3 lives instead of just 1, which will allow the player to progress through the game more. In the shop the player can upgrade the amount of lives they have(max of 5). After each wave their health returns to it’s maximum, but fuel will remain the same. In the power-ups tab, the player can increase the duration of each power-up by a maximum of 5 seconds. Once the player maxes out all 3 power-ups, they will unlock a feature called Super Nova were they can select one of the three power-ups to gain a new feature that will help the player survive new waves. Speaking of waves, the next change includes breaking up the game into multiple waves. This change allows the player to get a break between waves to upgrade their ship in the shop. This also makes the player feel like they are progressing through the game more.
🎉🎉MAJOR UPDATE🎉🎉: For the past few days I’ve been working on a few updates, which include finishing and balancing the new Super Nova feature. When you max out all 3 power-up upgrades, it allows you to super charge. One of them includes Double Shot, 2x score on top of 2x score, and buffs for a short amount of time after your shield breaks. I made waves infinitely and made them progressively harder with each passing wave. I added a slight amount of polish to the menu where a little click sound plays when you toggle settings or press a button. I realized that when the player got hit it wasn’t very noticeable since it played the same sound as when an enemy got hit, so I added screen shake which was something I wanted to add for a while but procrastinated it because the way I made my scrolling background with a Parallax background that had a Parallax layer and sprite 2D as a child so when I added the camera 2D node it stopped the background from scrolling so I had to delete all of that and update it with the newer method. But after an hour or so, I got it looking clean and was happy with it, so now when the player takes damage, there is a very noticeable shake to the screen, which helps indicate that you got hit. I also added this to the enemy, but you have to build up a fairly large consecutive hit counter to really notice it. I did start to work on a new tank enemy since all of the existing ones are relatively weak, so this one will have 5 HP, which is half of an asteroid, and will shoot double-shot bullets, which will be punishing if the player gets hit by it. Speaking of HP, instead of healing the player’s hearts back to their maximum amount despite the current amount, it now only heals you by one heart. Now normally, I would have a video to showcase all of these new features, but my thing is weird and will only take images, not videos, so sorry if it’s missing, like all of the updates.
Small Update: I just added a notes and acknowledgements page to replace the old broken leaderboard page. It just includes some writing and a link to my new Discord Page. If you want to join early to the launch, here’s the link: https://discord.gg/ccgyRZArYm
🎉🎉Major Update🎉🎉 After a little bit of playtesting, I came to the conclusion that the game needed to be much harder because it came up as a problem more often than not. I was already planning to add a few more enemy types, so it didn’t really matter. New Enemy Types 1) A horde of diver enemies 2) A large tank enemy that has double shots 3) A Suicider enemy which pathfinds to the player 4) An asteroid field that can spawn I also plan on adding a bomber enemy with explosions, and a flame thrower enemy which will deal more damage the longer you are in the flames and will burn your fuel. But because I was so close to the 10-hour limit, I have to make a devlog before continuing on it. I also decreased the wavelength from 30 seconds to just 20 because it made for a much faster-paced game and was easier on the player. In the future, I plan on adding a keybind option to the settings, which might take a while to figure out, bosses, which probably won’t happen, and a ton more polish to the menu because it looks terrible.
Fairly large update!!! Over the past few days, I’ve been working and have gotten quite a lot done. Recent changes include A new bomber enemy who appears on wave 15, dropping bombs as it passes through. Bombs have 3 seconds before exploding and deal the standard 1 HP. Then I polished the menu so that instead of having ugly buttons down at the bottom of the screen, I now have large transparent buttons right in the middle of the screen. I also made the buttons feel really juicy, changing color and playing a short clicking sound when hovered over with the mouse. I changed up the settings panel by adding some darker panels for detail and organization. Instead of the set WASD and arrow keys, I now have key binding as an option. I don’t know what other controls players would use, but just in case, and it also makes the game feel more polished. I think right now I plan on adding a stats page in the menu next that can showcase stuff like your highest wave, how many attempts, and enemies killed. But I think I’m going to save that for tomorrow. So for now, I’ll see you in the next devlog. :)
This morning, I’ve been working on adding a statistics menu to the menu, which keeps track of stuff like your highest wave or how many power-ups you’ve bought. All of the things are saved after closing the window, so not much has been added, but it’s something.
I’ve just been working on adding some finishing touches lately, most of which include working with the new log feature. Inside of it I have three different tabs Enemies which is just a list of all of the different enemies and their stats like hp and speed. The second one is for achievements. I have ten so far, which include: First Orbit, earned by playing for 15 mins. Deep Space Transit for 30 minutes, and Time Flies for an hour. Atmosphere Cleared for getting to wave 5. Flight Lieutenant for wave 15. Squadron Leader for wave 30, and Cosmic Anomaly for 50. Just Getting Warm for killing a thousand enemies. Determined I for dying 50 times and Determined II for dying 100 times. I also added some progress bars to visually show your progress towards the achievements. For the stats menu, all I changed was adding a darker panel behind all the stats to add some detail; other than that, that’s all I did. Also, the scrolling menus were almost my downfall.
Lately I’ve just been polishing the game. Nothing super interesting. I fixed the keybindings because when you selected a key with a long name like RightBracket, the label would expand into the button and overlap. I just made a better layout for it and made it so the text would be aligned on the right side, making it expand to the left instead. Then I worked on cleaning up some of my code since I’m planning on shipping tomorrow. Then I added a TON of polish to the main menu. I added a little rotating tip at the bottom and displayed your high score and highest wave at the top of the menu, which was easy enough. I still want to log at least two more hours, so if anyone has ideas, please let me know, because I’m out of ideas. Also, in the pictures, if the text looks sideways, it’s because I rotated it as a little animation. I think the current total for lines of code is 3005, if you’re interested, btw.
Finally finished the game!!! Just posting a quick devlog before shipping. I added satellites and space junk that can fly in from the right side of your screen, which adds an extra obstacle. The only hard part about it was figuring out some physics equations with Newton’s Law of Universal Gravitation. After that, it was finished. Here’s my code if you want to look at it(GDScript): extends Node2D var item = 0 var active_node: Node2D = null var velocity := Vector2.ZERO var rotation_speed := 0.0 var spawning_enabled := true const MIN_SPAWN_TIME = 10.0 const MAX_SPAWN_TIME = 15.0 const PLANET_POSITION = Vector2(300, 1500) const GRAVITY_STRENGTH = 450000.0 @onready var timer = $Timer @onready var small_satellite = $“Small satelltite” @onready var large_satellite = $“Large satellite” @onready var scrap = $Scrap func _ready() -> void: randomize_next_spawn_time() func _process(delta: float) -> void: if active_node and active_node.visible: var vector_to_planet = PLANET_POSITION - active_node.global_position var distance = vector_to_planet.length() var direction = vector_to_planet.normalized() var gravity_force = direction * (GRAVITY_STRENGTH / (distance * distance)) velocity += gravity_force * delta active_node.global_position += velocity * delta active_node.rotation += rotation_speed * delta if active_node.global_position.x < -150: disable_active_node() func _on_timer_timeout() -> void: randomize_next_spawn_time() if not spawning_enabled: return item = randi_range(1, 3) if item == 1: pick_small() elif item == 2: pick_large() else: pick_scrap() func randomize_next_spawn_time() -> void: if timer: timer.wait_time = randf_range(MIN_SPAWN_TIME, MAX_SPAWN_TIME) timer.start() func reset_and_launch(node: Node2D): disable_active_node() small_satellite.hide() large_satellite.hide() scrap.hide() node.show() node.global_position = Vector2(600, randi_range(0, 960)) velocity = Vector2(-150, -45) rotation_speed = randf_range(-1.5, 1.5) if node.has_method("set_deferred"): node.set_deferred("monitoring", true) node.set_deferred("monitorable", true) active_node = node func disable_active_node(): if active_node: active_node.hide() if active_node.has_method(“set_deferred”): active_node.set_deferred(“monitoring”, false) active_node.set_deferred(“monitorable”, false) func stop_spawning() -> void: spawning_enabled = false timer.stop() func start_spawning() -> void: spawning_enabled = true randomize_next_spawn_time() func pick_small(): reset_and_launch(small_satellite) func pick_large(): reset_and_launch(large_satellite) func pick_scrap(): reset_and_launch(scrap) func _on_scrap_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node() func _on_large_satellite_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node() func _on_small_satelltite_body_entered(body: Node2D) -> void: if body.has_method(“take_damage”): body.take_damage() disable_active_node()
Ships:
Hi! The project I’ve been working on is called Void Strike. It’s a space shooter game in which the player controls a spaceship and must survive hordes of enemy waves. The reason why I chose to create this game is that I thought it would be easy. Since I’ve never really used Godot, I thought I should start simple. By the end of working on it, I can confidently say that I’ve learned at least the basics of the engine. That’s all anyway. Have Fun! Also, last night when I was trying to add it to Itch.io, I accidentally overwrote LITERALLY ALL of my files and everything, so the only thing I have left is the HTML export, and the entire project on my Godot account is just gone, and I can’t recover it, so if there is anything a little buggy, that’s probably why. And I can’t do anything about it, sorry. I just decided to ship it as it currently is instead of not shipping it at all, since I’ve already spent too much of my time on this. Once more, I’m sorry....
|
1793004979.3407114
|
1793091379.3407114
|
|
49340
|
Ministom by @foxors | Stardance
|
foxors
|
1
|
103.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-30T19:54:08Z", "hours": 103.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I have made a mini game server for Minecraft from scratch with a java library called Minestom. Features include Supports Minecraft Java version 26.2 Different minigames A system which automaticly manages all game instances A queue system A party system A ban system An automatic bad word block list banner when players use words they really should not (must be configure over properties file) A report system A permission system Persistant reports/bans/permissions accross server restarts with sqlite database Configuration over properties file ooooor … by modifieng source code ;) Multible commands acting as a ‘frontend’ to all the systems some require specific permissions to execute A main program to connect everything Velocity support In game build tool to modify maps on the go Additional abilities that may be usefull fly in survival mode hide from other players change gamemode help command Visual ranks for players A console prompt that can be used to execute comands from console side NPC’s instead of commands in lobby Prebuild maps to play on for people who can’t test it normally, because the requirements are a bit messed up because it is multiplayer on a paid game please read my README.md file in my repo & watch [this broad video] ( https://foxors.de/files/ministomVideo.mp4 ) the most difficult things where Things i had to first figure out because Minestom has some methods without any javadoc nor comments in source code Another thing that was a bit frustrating was that i tried to make my own workflow with my own runner. However it did not go great and now you have to build docker images yourself, but do not worry i have made a compose and DockerFile all ready, which both worked for me. Learned a bit A great thing was that i learned a lot about Java in this project and i think it really helped me with my exam in university (our prof still makes corrections). PS: You may see the ai notice on this project. It points to a not finished part of this project which is not part of this build, just so you know :) Hope you enjoy!", "repo": "https://codeberg.org/Foxors/Ministom", "demo": "https://foxors.de/files/ministom.html"}]...
|
[{"post_id": 75636, "ts": "202 [{"post_id": 75636, "ts": "2026-09-30T16:43:16Z", "hours": 3.4489, "text": "Ready to ship? Context I have programmed, build and arranged a minigame server for Minecraft using a Java library called Minestom, which lets you create a minecraft server from scratch After more then 100 hours of work i think i am ready to do a first ship. This dev log is just about stuff i did to prepare. I added screenshots to my readme made the docker setup more easy. I filmed a little video showing some broad functionality of the server. Most loose ends are tied up and packet together. A release can be found in my forgejo instance & there is now a demo server on foxors.de:25565 The only problem is that the people who will rate this project will have a very hard time testing :(. Because they would need A: 2 Paid Minecraft java accounts or B: Set up the server on their machine and need to have the know how to play in offline mode. That is why i also made a little broad video and also put a bit of effort showing off in the README.md file in my repo. Hope someone will enjoy it :) ps if someone lives in around UTC+2 timezone i will happily play with them from 19 to 20 o’clock."}, {"post_id": 74572, "ts": "2026-09-27T17:30:11Z", "hours": 8.6217, "text": "Fixing up stuff Context : I am creating a mini game server for Minecraft with a java library called Minestom which allows the creation of servers for Minecraft Short summary Made new docker setup implementation deleted old docker setup and made new one added geyser and floodgate Created NPC’s in lobby that can be right clicked to join games Build map for color party game Now permissions of offline players can be changed Moved from anvil loader to polar/shematics Finally made server stop cleanly after /stop command is sent by players Redesigned the win/loose screen for each player Added some more error handling to specific commands Added /stat command to see some stats in game about the server New docker setup Last time i didn’t get quite how to build a docker file inside my workflow and now i don’t even try again because time . What i did is that i have a docker directory now bundled into each build zip which contains all files needed to create a Dockerfile + a bash file to download required files from other projects like velocity proxy. + A compose file which works more or less out of the box. Non Playable Characters I finally filled my diamond blocks in my lobby with some NPC’s. Those can be interacted with instead of having to use /queue join <game> . I also did the skins of two of those. The other one is only slightly modified and the last one is the same guy from Hypixel’s TNT-Run NPC, because it was 23 o’clock and i wanted to go to sleep . What funny was that i forgot to disable my cape when i configured them with my account appearance data. They actually still have them on but i turned them invisible. Anvil to polar Anvil is the same system original Minecraft uses with region files. But those region files store a lot more data (air) than i need. So i switched to polar a community addon for Minestom that adds support to load from a shematic file instead which only stores the blocks i need. New win/loose screens Now not only is it displayed in chat who won but also we got 1., 2. and 3. place positions in case you want to know how close you missed first. Ship? Maybe?! I still try to get Minecraft bedrock running on linux because i don’t want to trust a stranger on flathub who is not verified & i wanted bedrock support but can’t test it right now :( ps: if anyone wants to try it out i would greatly appreciate it :) in a few days i will have fully set up a server on my server under foxors.de. But only java edition for now because of the bedrock thing on linux"}, {"post_id": 72099, "ts": "2026-09-22T05:17:54Z", "hours": 9.5008, "text": "No time left for luanti server programming :( Context : I am programming a server for Minecraft with a java library called Minestom. I plan to make a minigame server. The plan turned out to also now program functionality for supporting luanti/minetest players. To be honest i don’t think i can make everything fully work with luanti until the end of stardance. That is why i will focus more on getting everything shipped now. Sadly only for Minecraft, so some of you can’t play :(. But i want to still continue this project after stardance ends and maybe someday i get it to work. The current state of luanti support I managed to parse some more specific parts of each packet. But as you can see in the video i am not finished with the init sequence. What i have done is the init, authantication, version selection and some more smaller thingis. The rest would be to send over item, node, wheather, time etc. data which all use custom data objects and don’t have any documantation so i need to figure it out from like 6 different c++ files. Minigames I started programming on the server again. Now i have made a color party game where you have to stay on the right color and the rest disappears. And I refined my snowball game, where you have to hit other players from the map. Now the snowballs automatically despawn. Fin What the hell was with last post? 200 views?!?! is it because i have an terminal emulator open? or because “server” is in the title? ;) PS: Had to post again because of time limit of 10 hours."}, {"post_id": 67283, "ts": "2026-09-13T10:59:31Z", "hours": 10.6894, "text": "Trying to create a Luanti server in java+ need to devlog because of 10 hours time limit Soooo i don’t have anything to show. I can only tell you that is stupidly hard to create the protocol implementation of luanti if the entire docs to it is one page in the wiki and the rest c++ source code. Now i not only learning java but also c++. Could be worse because i already know C. Talking about slight progress You can see in the video below a demonstration of a UDP socket receiving data from the actual Luanti client. As you can see i already managed to parse some parts of the protocol. Currntly i am sitting on refining this a bit + implementing the init process. Till now i only managed to set the peerId of the luanti client. (peerId is, when i understood correctly, just an id the server gives clients to track them. After a client recieves this id it uses it to contact the server next time)"}, {"post_id": 64344, "ts": "2026-09-08T17:25:15Z", "hours": 8.4444, "text": "I totally not know what title i should write down Context I am trieng to create a mini game server for Minecraft with the help of Minestom which is a java library toolkit to create servers from scratch I only have minor changes to tell you because I am working on a BIG thing right now but i don’t know if it is going to work. But this is what i have added/changed Added teleport command to throw my friend around while testing because they are non technical and somehow don’t get used to the commands i made :( Made banned players get kicked while in the login phase instead of when they are already logged in Added a line shape to my in game world editor Now the world editor takes care of worlds itself instead of having to work with messy code working with the default games manager thing i created Created a rank. Players can now have ranks like idk “admin” or “dev” & so on. They are only visual in the tab list and everywhere else their names are. and i had fun with redo/undo feature of the in game editor as you can see in the pictures"}, {"post_id": 59146, "ts": "2026-08-31T19:29:53Z", "hours": 5.2194, "text": "I like snow Context I am creating a mini game server for Minecraft with a java library named Minestom which allows you to create a server from scratch for Minecraft Today i continued programming my in world editor. Now you can copy & paste structures. You also can now create a sphere if you want. The snow thing in the title is about the newest game. A snow ball fight game where you have to throw others from the map by throwing snow balls. Did you know that snow balls are not real projectiles because they can’t hit players. It is a bit hard to make them hit players. I also made the map for the spleef game & already created a map for the snow ball fight game. Both were now made with my own in game editor without additional tools."}, {"post_id": 58385, "ts": "2026-08-30T19:53:15Z", "hours": 2.2886, "text": "CTRL+Z would be useful i think Context I am creating my own mini game server for Minecraft withe Minestom, a java library to create your own server for Minecraft from scratch. I managed to get the build tool to a moderate level of usability. You can now: select an area over wooden axe over pos1 and pos2 command fill selected area setblock at specific position replace blocks in selected area undo & redo actions you did give yourself an item you need and don’t find in creative menu like a light block or a command block or something I also made the world where you can edit maps calculate light in the world. Thanks to that i managed to fix some light issues i had previously with my lobby map. Now i don’t have to give all player night vision the entire time."}, {"post_id": 57523, "ts": "2026-08-29T18:08:46Z", "hours": 6.3056, "text": "Programming a in game world editor because i am too lazy to create server code for axiom or other tools Context I am creating a custom mini game server for Minecraft with Minestom A library allowing to write a java Minecraft server from scratch Today i spent most of my time building a in game world editor functioning similar to the popular world edit plugin. My little twist is that i use the new displayblocks Minecraft offers to make a visual appealing selection box of what you selected. It is ridicules how long it took me >:( I also made it possible to load specific worlds and edit them which are saved after you are finished this way i could for example modify the TntRun game world a bit to my liking while the server runs but these modifications made are permanent. Normally worlds don’t get saved after the mini game is finished. So now i could just rely on my own tools instead of having to create a world in vanilla Minecraft and then import them into my Minestom project. I also touched the idea of trying to implement protocol code of Luanti or formally known as Minetest which works with Minestom to let players join through Minetest for people who don’t want to use proprietary applications or don’t have an account for regular Minecraft. But i will probably fail at that task because it is waaay over my head :|"}, {"post_id": 56869, "ts": "2026-08-28T20:58:37Z", "hours": 16.1525, "text": "Oh no i forgot to do a post 👀 Well, here we are 16 hours in… again. Context I am programming a mini game server for Minecraft with Minestom, a library which allows me to create my own server from scratch. (in java) Overview of what i have done Added a server side console where an administrator can input commands which the server executes with a library called jLine Tried making a workflow for automatically building with some success Made a Spleef game prototype Improved the ghost player system Made a ui makeover for chat elements (again again) Added some new abilities/commands Server side console I have added a console thing where, after the server started, somebody with access to the terminal can run commands as the server with all permissions. For that i used a lib called jLine to make it just like the consoles most Minecraft server administrators should be familiar with. The actual hard part was that i had to rewrite some of the code i already have done. For example commands that would only work if they where run by a player needed now to check first if the command caller is the server actually itself. Actions I never used github actions or something like that. So i did the normal thing and created a runner for my own forgejo git instance and build an action without understanding more than 60% of it or even less. While i did not manage to create a docker build process i managed to create an action which builds my gradle java project with shadowjar and puts all required files into a zip which gets saved to my repo as an artifact file to be downloaded and executed instantly. turns out it is really dumb to try create an action on an runner which uses podman which uses docker in docker in a container which now should have installed docker inside of that to build an image? IDK man i have to sleep at some point Ghosts I have already made a system letting games make players ghosts who can’t interact with the world around them. Now i have made it like hypixel does it. Players are getting hidden from all other players. Not by giving them an invisible potion or something. The server lets players disappear by just not sending information about their whereabouts to the other players oh and they are in a survival mode but can still fly. TO NOT LET THEM ESCAPE MUHAHA i am evil or something. Oh and new commands I have made small commands which i though would be fun. hide Tell server to hide your player account by the same principle as the ghost system. fly Enable flying for your player account. stop Literally stops the server help A help command which tells players all about the commands they can access with their permissions nickname Kicks you but after joining again you will be logged in as another account name with the others skin etc. Only your uuid will stay the same to still be able to fetch your accurate permission etc. on the server. (of course this and most of the others commands on this level are behind permissions and can’t be accessed that easily) By, by Hope you have a great rest of a good day! I am currently on vacation and therefore have to use my Labtop instead of my PC. I already miss him i just tried another linux distro on it :("}, {"post_id": 51325, "ts": "2026-08-20T22:12:05Z", "hours": 7.5578, "text": "Security Context I am creating a custom mini game server for Minecraft with Minestom. A library allowing to write a java Minecraft server from scratch Security is one of my least favorite thing because it is sooooooooo complicated to get done right but this time it is not about security for protecting the server itself. It is about user security. Banning Every public server (sometimes also private ones) need a ban system. I now have implemented one which allows banning players even if they are not on the server by using Mojang’s public API to get the uuid of players with their name. This uuid gets saved alongside a ban time and a reason for the ban to the sqlite database. The players are also automatically kicked when the writing to the database happens. Each time players try to connect to the server it first checks if they are banned or not. If yes they kick them instantly again with information for them about how long the ban is etc. Players get also automatically unbanned if they ban time runs out. Or an player with sufficiant permissions can unban them over /unban unban <player> manually. Permanent bans are also possible by telling the server the ban time is 0. Report system Players can now report others with a reason. Administrators can then look up all open reports not handled by another administrator. They can view information about the report like who is reported, when is reported, why is reported. After they have researched if the player actually made something stupid they can react to it and tell the report system to archive the report and tell a reason/a explanation on how/why it is fixed now for future administrator actions to look at. Chats Going to a more fun little thing. Now every player can only chat with other players in the same world/crate/game/whateveryouwannecallthem so that not all players are getting flooded by messages by ALL players of the ENTIRE server. Auto banning I also gone ahead and made a system which checks those chat messages before sending them to other players for words from a word blacklist configured in the server configuration. If a match is found the player who send that message gets instantly banned for using a blacklisted word. This is just basic security from people using bad/horrible words in chat for/with others. When the system maybe fail to detect something because players are probably starting using cryptic things to express words we also have the report system and the logs made from those chat conversation which can be viewed by server administration."}, {"post_id": 50270, "ts": "2026-08-19T13:00:37Z", "hours": 8.1297, "text": "Let me just shortly re implement everything Context I am creating a custom mini game server for Minecraft with Minestom A library allowing to write a java Minecraft server from scratch Overview Yesterday and today i did this here Now hard coded values are instead read from properties file Made nearly all commands rely on same design in chat to look good Players who disconnect also leave queues now automatically On shutdown the server actually closes things like THE DATABASE CONNECTION :| Made queue reset if players leave while in start sequence Made a little game loop system for all games (countdown to start/countdown to end) Create auto completion for queue- & permissions command Rewrote large portions of the queue and party system Config file I now use the same thing for config files the official Minecraft server uses. .properties . It is actually a library provided by java and does not use any other dependencies. Same design everywhere to feel at home Mostly all commands now rely on the same design in the chat to make it look more consistent. Disconnecting players I have made a event handler for player disconnection which tells the queue and party system to kick this player from their system. Because you should not be in a party with someone who is not on the server. Actually handling shutdown now Previously the server just terminated everything including the database connection :| now Minestom sends my program a signal and i gracefully close database, kick players and so on. Game loop system Just a small collection of functions helping with standard game presidia like starting after 5 seconds or sending all players back to the lobby after 10 seconds. Auto completion I added auto completion to commands the user will interact with to make it easier. Rewriting CoDe YAY my favorite thing. My original code was kind of spaghetti code and now i rewrote large portions which should improve understand ability? The hardest thing Probably the hardest thing i am facing with this project is Minestom’s lack of documentation. It has a wiki which only covers the basics. The rest is java doc but many functions/variables are defined like this: this_specific_thing() Does this_specific_thing but doesn’t tell what this_specific_thing is. But thankfully Minestom is open source so i can just look at the source code thought it is a bit hard for me because i am still somewhat of a java newbie."}, {"post_id": 49403, "ts": "2026-08-18T06:40:31Z", "hours": 5.7286, "text": "The first mini game Context I am creating a custom mini game server for minecraft with Minestom A library allowing to write a java Minecraft server from scratch. Cleaned up on blueprints & crates management I rewrote parts of the logic of crates (system to manage mini games). To be hopefully better maintainable. Tnt Run I made a first game the classic TntRun. Players are on a floor which disappears under their feed. There are 3 floors and it is checked who has won. I also had a bit fun with the light engine at the start (first image) Jar I made everything, including dependencies, able to be build into a single jar with shadow jar. Docker/Podman I used my jar to create a Docker image file which takes everything important from the repo & puts it into a docker/podman image (only tested with podman). I also made an environment variable that can be set which gives a specific player the highest admin permissions. So that you don’t have to mount the container & manually change add a player to the permission table of the SQLite database in it. Ghost system I also made 3 functions to implement a basic ghost system for when games want to get rid of players from the game. And an readme I added a README.md to my repo… with some text about how this thing works and breaths."}, {"post_id": 48752, "ts": "2026-08-17T08:58:10Z", "hours": 5.6761, "text": "Procrastinating with design over function Consistent chat UI So today i made a consistent chat design for different parts of the server. Except admin tools those still need to get a makeover. Queue upgrade Furthermore I added a bit of UI for the queue to tell players how full the queue is and how long it will take to start. I also made the queue wait for a few seconds before actually starting to give other players to join if the game can start but also works with more players. terrain loading screen This was such a paaaiinnn i didn’t find any documentation that is up to date. After some digging i found out the Minecraft client shows users the loading screen for change worlds if the dimension is changed NOT THE WORLD THE DIMENSION so i made a dimension… again a bit painful because docs are kinde not existing? But… i guess the source code is enough docs :). The reason why i wanted a loading screen on client side when changing worlds is to hide some ugly chunk glitching that happens sometimes and hopefully not to confuse the client too much about in which world it actually now is. In addition I had fun with dimension parameters and accidentally made a horror map."}, {"post_id": 48027, "ts": "2026-08-16T09:58:04Z", "hours": 5.6528, "text": "I kinde forgot to install hackatime extension for Vscode _ (° - °)_/ … but 5 hours are still some hours. But now to get your introduced to what i already have managed to create. A server A system to dynamically manage different worlds, which will host different games in future A queue system for games A party system A lobby A permission system sooommeee chat UI stuff to look okay Permissions get saved to sqllite database So yea a bit of stuff are already on their way. Dynamically managing of different worlds I have made a system that can on command create/remove worlds and move players to them. Furthermore it also removes automatically old worlds with no players in them to save on resources. I call worlds crates because they are a bit self contained. Queue system On top of the crateManager i build a queue system. Players can join queues for a game and if a queue has enough players it creates the crate for it and moves all players to it. In the crate they can than play bc the crates have their own self contained logic. Party system Players can all join together in a party and if they queue they always get into the SAME queue. Permission system I have made a permission system. Players can get permissions like admin.build.place to for example be allowed to place blocks in normally non build areas. But they can’t break any blocks that would also require admin.build.break or instead of having to give both permissions you can just give a player admin.build and they will have all permissions of sub permissions of build. Each permissions is saved/read from/to a sqllite database to make them persistent across server reboots. lobby oh yea and i did spend around 3 hours building a lobby :))))"}]...
|
Title: Ministom by @foxors | Stardance
Devlogs:
I Title: Ministom by @foxors | Stardance
Devlogs:
I kinde forgot to install hackatime extension for Vscode _ (° - °)_/ … but 5 hours are still some hours. But now to get your introduced to what i already have managed to create. A server A system to dynamically manage different worlds, which will host different games in future A queue system for games A party system A lobby A permission system sooommeee chat UI stuff to look okay Permissions get saved to sqllite database So yea a bit of stuff are already on their way. Dynamically managing of different worlds I have made a system that can on command create/remove worlds and move players to them. Furthermore it also removes automatically old worlds with no players in them to save on resources. I call worlds crates because they are a bit self contained. Queue system On top of the crateManager i build a queue system. Players can join queues for a game and if a queue has enough players it creates the crate for it and moves all players to it. In the crate they can than play bc the crates have their own self contained logic. Party system Players can all join together in a party and if they queue they always get into the SAME queue. Permission system I have made a permission system. Players can get permissions like admin.build.place to for example be allowed to place blocks in normally non build areas. But they can’t break any blocks that would also require admin.build.break or instead of having to give both permissions you can just give a player admin.build and they will have all permissions of sub permissions of build. Each permissions is saved/read from/to a sqllite database to make them persistent across server reboots. lobby oh yea and i did spend around 3 hours building a lobby :))))
Procrastinating with design over function Consistent chat UI So today i made a consistent chat design for different parts of the server. Except admin tools those still need to get a makeover. Queue upgrade Furthermore I added a bit of UI for the queue to tell players how full the queue is and how long it will take to start. I also made the queue wait for a few seconds before actually starting to give other players to join if the game can start but also works with more players. terrain loading screen This was such a paaaiinnn i didn’t find any documentation that is up to date. After some digging i found out the Minecraft client shows users the loading screen for change worlds if the dimension is changed NOT THE WORLD THE DIMENSION so i made a dimension… again a bit painful because docs are kinde not existing? But… i guess the source code is enough docs :). The reason why i wanted a loading screen on client side when changing worlds is to hide some ugly chunk glitching that happens sometimes and hopefully not to confuse the client too much about in which world it actually now is. In addition I had fun with dimension parameters and accidentally made a horror map.
The first mini game Context I am creating a custom mini game server for minecraft with Minestom A library allowing to write a java Minecraft server from scratch. Cleaned up on blueprints & crates management I rewrote parts of the logic of crates (system to manage mini games). To be hopefully better maintainable. Tnt Run I made a first game the classic TntRun. Players are on a floor which disappears under their feed. There are 3 floors and it is checked who has won. I also had a bit fun with the light engine at the start (first image) Jar I made everything, including dependencies, able to be build into a single jar with shadow jar. Docker/Podman I used my jar to create a Docker image file which takes everything important from the repo & puts it into a docker/podman image (only tested with podman). I also made an environment variable that can be set which gives a specific player the highest admin permissions. So that you don’t have to mount the container & manually change add a player to the permission table of the SQLite database in it. Ghost system I also made 3 functions to implement a basic ghost system for when games want to get rid of players from the game. And an readme I added a README.md to my repo… with some text about how this thing works and breaths.
Let me just shortly re implement everything Context I am creating a custom mini game server for Minecraft with Minestom A library allowing to write a java Minecraft server from scratch Overview Yesterday and today i did this here Now hard coded values are instead read from properties file Made nearly all commands rely on same design in chat to look good Players who disconnect also leave queues now automatically On shutdown the server actually closes things like THE DATABASE CONNECTION :| Made queue reset if players leave while in start sequence Made a little game loop system for all games (countdown to start/countdown to end) Create auto completion for queue- & permissions command Rewrote large portions of the queue and party system Config file I now use the same thing for config files the official Minecraft server uses. .properties . It is actually a library provided by java and does not use any other dependencies. Same design everywhere to feel at home Mostly all commands now rely on the same design in the chat to make it look more consistent. Disconnecting players I have made a event handler for player disconnection which tells the queue and party system to kick this player from their system. Because you should not be in a party with someone who is not on the server. Actually handling shutdown now Previously the server just terminated everything including the database connection :| now Minestom sends my program a signal and i gracefully close database, kick players and so on. Game loop system Just a small collection of functions helping with standard game presidia like starting after 5 seconds or sending all players back to the lobby after 10 seconds. Auto completion I added auto completion to commands the user will interact with to make it easier. Rewriting CoDe YAY my favorite thing. My original code was kind of spaghetti code and now i rewrote large portions which should improve understand ability? The hardest thing Probably the hardest thing i am facing with this project is Minestom’s lack of documentation. It has a wiki which only covers the basics. The rest is java doc but many functions/variables are defined like this: this_specific_thing() Does this_specific_thing but doesn’t tell what this_specific_thing is. But thankfully Minestom is open source so i can just look at the source code thought it is a bit hard for me because i am still somewhat of a java newbie.
Security Context I am creating a custom mini game server for Minecraft with Minestom. A library allowing to write a java Minecraft server from scratch Security is one of my least favorite thing because it is sooooooooo complicated to get done right but this time it is not about security for protecting the server itself. It is about user security. Banning Every public server (sometimes also private ones) need a ban system. I now have implemented one which allows banning players even if they are not on the server by using Mojang’s public API to get the uuid of players with their name. This uuid gets saved alongside a ban time and a reason for the ban to the sqlite database. The players are also automatically kicked when the writing to the database happens. Each time players try to connect to the server it first checks if they are banned or not. If yes they kick them instantly again with information for them about how long the ban is etc. Players get also automatically unbanned if they ban time runs out. Or an player with sufficiant permissions can unban them over /unban unban <player> manually. Permanent bans are also possible by telling the server the ban time is 0. Report system Players can now report others with a reason. Administrators can then look up all open reports not handled by another administrator. They can view information about the report like who is reported, when is reported, why is reported. After they have researched if the player actually made something stupid they can react to it and tell the report system to archive the report and tell a reason/a explanation on how/why it is fixed now for future administrator actions to look at. Chats Going to a more fun little thing. Now every player can only chat with other players in the same world/crate/game/whateveryouwannecallthem so that not all players are getting flooded by messages by ALL players of the ENTIRE server. Auto banning I also gone ahead and made a system which checks those chat messages before sending them to other players for words from a word blacklist configured in the server configuration. If a match is found the player who send that message gets instantly banned for using a blacklisted word. This is just basic security from people using bad/horrible words in chat for/with others. When the system maybe fail to detect something because players are probably starting using cryptic things to express words we also have the report system and the logs made from those chat conversation which can be viewed by server administration.
Oh no i forgot to do a post 👀 Well, here we are 16 hours in… again. Context I am programming a mini game server for Minecraft with Minestom, a library which allows me to create my own server from scratch. (in java) Overview of what i have done Added a server side console where an administrator can input commands which the server executes with a library called jLine Tried making a workflow for automatically building with some success Made a Spleef game prototype Improved the ghost player system Made a ui makeover for chat elements (again again) Added some new abilities/commands Server side console I have added a console thing where, after the server started, somebody with access to the terminal can run commands as the server with all permissions. For that i used a lib called jLine to make it just like the consoles most Minecraft server administrators should be familiar with. The actual hard part was that i had to rewrite some of the code i already have done. For example commands that would only work if they where run by a player needed now to check first if the command caller is the server actually itself. Actions I never used github actions or something like that. So i did the normal thing and created a runner for my own forgejo git instance and build an action without understanding more than 60% of it or even less. While i did not manage to create a docker build process i managed to create an action which builds my gradle java project with shadowjar and puts all required files into a zip which gets saved to my repo as an artifact file to be downloaded and executed instantly. turns out it is really dumb to try create an action on an runner which uses podman which uses docker in docker in a container which now should have installed docker inside of that to build an image? IDK man i have to sleep at some point Ghosts I have already made a system letting games make players ghosts who can’t interact with the world around them. Now i have made it like hypixel does it. Players are getting hidden from all other players. Not by giving them an invisible potion or something. The server lets players disappear by just not sending information about their whereabouts to the other players oh and they are in a survival mode but can still fly. TO NOT LET THEM ESCAPE MUHAHA i am evil or something. Oh and new commands I have made small commands which i though would be fun. hide Tell server to hide your player account by the same principle as the ghost system. fly Enable flying for your player account. stop Literally stops the server help A help command which tells players all about the commands they can access with their permissions nickname Kicks you but after joining again you will be logged in as another account name with the others skin etc. Only your uuid will stay the same to still be able to fetch your accurate permission etc. on the server. (of course this and most of the others commands on this level are behind permissions and can’t be accessed that easily) By, by Hope you have a great rest of a good day! I am currently on vacation and therefore have to use my Labtop instead of my PC. I already miss him i just tried another linux distro on it :(
Programming a in game world editor because i am too lazy to create server code for axiom or other tools Context I am creating a custom mini game server for Minecraft with Minestom A library allowing to write a java Minecraft server from scratch Today i spent most of my time building a in game world editor functioning similar to the popular world edit plugin. My little twist is that i use the new displayblocks Minecraft offers to make a visual appealing selection box of what you selected. It is ridicules how long it took me >:( I also made it possible to load specific worlds and edit them which are saved after you are finished this way i could for example modify the TntRun game world a bit to my liking while the server runs but these modifications made are permanent. Normally worlds don’t get saved after the mini game is finished. So now i could just rely on my own tools instead of having to create a world in vanilla Minecraft and then import them into my Minestom project. I also touched the idea of trying to implement protocol code of Luanti or formally known as Minetest which works with Minestom to let players join through Minetest for people who don’t want to use proprietary applications or don’t have an account for regular Minecraft. But i will probably fail at that task because it is waaay over my head :|
CTRL+Z would be useful i think Context I am creating my own mini game server for Minecraft withe Minestom, a java library to create your own server for Minecraft from scratch. I managed to get the build tool to a moderate level of usability. You can now: select an area over wooden axe over pos1 and pos2 command fill selected area setblock at specific position replace blocks in selected area undo & redo actions you did give yourself an item you need and don’t find in creative menu like a light block or a command block or something I also made the world where you can edit maps calculate light in the world. Thanks to that i managed to fix some light issues i had previously with my lobby map. Now i don’t have to give all player night vision the entire time.
I like snow Context I am creating a mini game server for Minecraft with a java library named Minestom which allows you to create a server from scratch for Minecraft Today i continued programming my in world editor. Now you can copy & paste structures. You also can now create a sphere if you want. The snow thing in the title is about the newest game. A snow ball fight game where you have to throw others from the map by throwing snow balls. Did you know that snow balls are not real projectiles because they can’t hit players. It is a bit hard to make them hit players. I also made the map for the spleef game & already created a map for the snow ball fight game. Both were now made with my own in game editor without additional tools.
I totally not know what title i should write down Context I am trieng to create a mini game server for Minecraft with the help of Minestom which is a java library toolkit to create servers from scratch I only have minor changes to tell you because I am working on a BIG thing right now but i don’t know if it is going to work. But this is what i have added/changed Added teleport command to throw my friend around while testing because they are non technical and somehow don’t get used to the commands i made :( Made banned players get kicked while in the login phase instead of when they are already logged in Added a line shape to my in game world editor Now the world editor takes care of worlds itself instead of having to work with messy code working with the default games manager thing i created Created a rank. Players can now have ranks like idk “admin” or “dev” & so on. They are only visual in the tab list and everywhere else their names are. and i had fun with redo/undo feature of the in game editor as you can see in the pictures
Trying to create a Luanti server in java+ need to devlog because of 10 hours time limit Soooo i don’t have anything to show. I can only tell you that is stupidly hard to create the protocol implementation of luanti if the entire docs to it is one page in the wiki and the rest c++ source code. Now i not only learning java but also c++. Could be worse because i already know C. Talking about slight progress You can see in the video below a demonstration of a UDP socket receiving data from the actual Luanti client. As you can see i already managed to parse some parts of the protocol. Currntly i am sitting on refining this a bit + implementing the init process. Till now i only managed to set the peerId of the luanti client. (peerId is, when i understood correctly, just an id the server gives clients to track them. After a client recieves this id it uses it to contact the server next time)
No time left for luanti server programming :( Context : I am programming a server for Minecraft with a java library called Minestom. I plan to make a minigame server. The plan turned out to also now program functionality for supporting luanti/minetest players. To be honest i don’t think i can make everything fully work with luanti until the end of stardance. That is why i will focus more on getting everything shipped now. Sadly only for Minecraft, so some of you can’t play :(. But i want to still continue this project after stardance ends and maybe someday i get it to work. The current state of luanti support I managed to parse some more specific parts of each packet. But as you can see in the video i am not finished with the init sequence. What i have done is the init, authantication, version selection and some more smaller thingis. The rest would be to send over item, node, wheather, time etc. data which all use custom data objects and don’t have any documantation so i need to figure it out from like 6 different c++ files. Minigames I started programming on the server again. Now i have made a color party game where you have to stay on the right color and the rest disappears. And I refined my snowball game, where you have to hit other players from the map. Now the snowballs automatically despawn. Fin What the hell was with last post? 200 views?!?! is it because i have an terminal emulator open? or because “server” is in the title? ;) PS: Had to post again because of time limit of 10 hours.
Fixing up stuff Context : I am creating a mini game server for Minecraft with a java library called Minestom which allows the creation of servers for Minecraft Short summary Made new docker setup implementation deleted old docker setup and made new one added geyser and floodgate Created NPC’s in lobby that can be right clicked to join games Build map for color party game Now permissions of offline players can be changed Moved from anvil loader to polar/shematics Finally made server stop cleanly after /stop command is sent by players Redesigned the win/loose screen for each player Added some more error handling to specific commands Added /stat command to see some stats in game about the server New docker setup Last time i didn’t get quite how to build a docker file inside my workflow and now i don’t even try again because time . What i did is that i have a docker directory now bundled into each build zip which contains all files needed to create a Dockerfile + a bash file to download required files from other projects like velocity proxy. + A compose file which works more or less out of the box. Non Playable Characters I finally filled my diamond blocks in my lobby with some NPC’s. Those can be interacted with instead of having to use /queue join <game> . I also did the skins of two of those. The other one is only slightly modified and the last one is the same guy from Hypixel’s TNT-Run NPC, because it was 23 o’clock and i wanted to go to sleep . What funny was that i forgot to disable my cape when i configured them with my account appearance data. They actually still have them on but i turned them invisible. Anvil to polar Anvil is the same system original Minecraft uses with region files. But those region files store a lot more data (air) than i need. So i switched to polar a community addon for Minestom that adds support to load from a shematic file instead which only stores the blocks i need. New win/loose screens Now not only is it displayed in chat who won but also we got 1., 2. and 3. place positions in case you want to know how close you missed first. Ship? Maybe?! I still try to get Minecraft bedrock running on linux because i don’t want to trust a stranger on flathub who is not verified & i wanted bedrock support but can’t test it right now :( ps: if anyone wants to try it out i would greatly appreciate it :) in a few days i will have fully set up a server on my server under foxors.de. But only java edition for now because of the bedrock thing on linux
Ready to ship? Context I have programmed, build and arranged a minigame server for Minecraft using a Java library called Minestom, which lets you create a minecraft server from scratch After more then 100 hours of work i think i am ready to do a first ship. This dev log is just about stuff i did to prepare. I added screenshots to my readme made the docker setup more easy. I filmed a little video showing some broad functionality of the server. Most loose ends are tied up and packet together. A release can be found in my forgejo instance & there is now a demo server on foxors.de:25565 The only problem is that the people who will rate this project will have a very hard time testing :(. Because they would need A: 2 Paid Minecraft java accounts or B: Set up the server on their machine and need to have the know how to play in offline mode. That is why i also made a little broad video and also put a bit of effort showing off in the README.md file in my repo. Hope someone will enjoy it :) ps if someone lives in around UTC+2 timezone i will happily play with them from 19 to 20 o’clock.
Ships:
I have made a mini game server for Minecraft from scratch with a java library called Minestom. Features include Supports Minecraft Java version 26.2 Different minigames A system which automaticly manages all game instances A queue system A party system A ban system An automatic bad word block list banner when players use words they really should not (must be configure over properties file) A report system A permission system Persistant reports/bans/permissions accross server restarts with sqlite database Configuration over properties file ooooor … by modifieng source code ;) Multible commands acting as a ‘frontend’ to all the systems some require specific permissions to execute A main program to connect everything Velocity support In game build tool to modify maps on the go Additional abilities that may be usefull fly in survival mode hide from other players change gamemode help command Visual ranks for players A console prompt that can be used to execute comands from console side NPC’s instead of commands in lobby Prebuild maps to play on for people who can’t test it normally, because the requirements are a bit messed up because it is multiplayer on a paid game please read my README.md file in my repo & watch [this broad video] ( https://foxors.de/files/ministomVideo.mp4 ) the most difficult things where Things i had to first figure out because Minestom has some methods without any javadoc nor comments in source code Another thing that was a bit frustrating was that i tried to make my own workflow with my own runner. However it did not go great and now you have to build docker images yourself, but do not worry i have made a compose and DockerFile all ready, which both worked for me. Learned a bit A great thing was that i learned a lot about Java in this project and i think it really helped me with my exam in university (our prof still makes corrections). PS: You may see the ai notice on this project. It points to a not finished part of this project which is not part of this build, just so you know :) Hope you enjoy!...
|
1793004682.237409
|
1793091082.237409
|
|
22328
|
HEXAPOD/SPIDER ROBOT 2.O by @Vedaprotoshredhq | St HEXAPOD/SPIDER ROBOT 2.O by @Vedaprotoshredhq | Stardance...
|
Vedaprotoshredhq
|
0
|
102.61
|
0
|
[]
|
[{"post_id": 57531, "ts": "202 [{"post_id": 57531, "ts": "2026-08-29T18:18:45Z", "hours": 1.6947, "text": "ASSEMBLING PARTS! Okay so, I assembled parts, like I tried assembling parts in pieces, Like body to coxa motor then coxa motor horn to femur then femur motor horn to tibia then tibia motor horn to leg and then leg to ground shock sensor. Like I will try to make a complete assembly but maybe my laptop won’t be able to handle it. But still, I will try complete assembly if possible. Subscribe YouTube Instagram"}, {"post_id": 51142, "ts": "2026-08-20T17:15:30Z", "hours": 2.6747, "text": "A DIFFERENT KIND OF SHOCK ABSORBER AND REBUILD FEMUR PARTS! Okay, so I made a very simple design for the new shock absorber, but I will just be using tpu instead of pla, do I guess that I should work. And rebuild and modified all femur parts as they were all short in length. And made go through space for servo wires in body and tibia. Subscribe YouTube Instagram"}, {"post_id": 50442, "ts": "2026-08-19T16:34:13Z", "hours": 6.2031, "text": "MAKING NEW SHOCK ABSORBER AND REPAIRING PARTS! So, i remade the shock absorber again and after 6 failed variations made another 4 today and repaired few parts and making the new shock absorber took a lot of time. Subscribe YouTube Instagram"}, {"post_id": 49809, "ts": "2026-08-18T19:09:19Z", "hours": 2.1506, "text": "REPAIRING AND UPDATING PARTS. So, like there were few parts which I made wrong and few needs to be upgraded so I didn’t repaired few parts and ungraded this whole part. Subscribe YouTube Instagram"}, {"post_id": 49185, "ts": "2026-08-17T20:29:39Z", "hours": 3.8667, "text": "1ST TEST LEG And MISTAKES! So, i finally got the first test leg 3d printed from a local 3d printing service by my own money. I order all the parts of a whole single leg and few different different variants for shock absorber but non of them worked. And also I tried assembling the leg but wasn’t able to as I didn’t had screws for it , and there were few or maybe more then few 😅 mistakes in it ,and some parts need to be improved, so I wrote everything I have to change and also I forgot that I wanted 3-4 exactly same parts in more then 1 quantity so wrote that also, so will now again edit or redesign parts. Subscribe YouTube Instagram"}, {"post_id": 47553, "ts": "2026-08-15T15:06:11Z", "hours": 3.1167, "text": "FINALL! BODY FOR THE HEXAPOD 2.0 MORE TORQUE LEGS! So, finally after 3-4 tries body for the mg996r servo with more torque leg version is completed as I wrote in previous devlog i tried to make spider net kind of bottom bed and made windows and x shape windows so that it can have less weight and good strength. Subscribe YouTube Instagram"}, {"post_id": 47147, "ts": "2026-08-14T20:30:23Z", "hours": 2.3661, "text": "MORE TORQUE LEG BODY DESIGN! So, made the whole body again and made it at origin this time and now was trying to make the spider web kind of structure for the bottom layer and it’s all so much messed up, but I think I will be able to do it so will try. Subscribe YouTube Instagram"}, {"post_id": 46528, "ts": "2026-08-13T20:23:42Z", "hours": 1.5, "text": "😭😭divided into in 1/4th and did a lot of work, made coxa part brackets and made a lot of triangles for the triangular structure like bottom and then later on realised that it’s center is not on origin so it was all waste and will have to made the whole body from scratch again😭😭 Subscribe YouTube Instagram"}, {"post_id": 45985, "ts": "2026-08-12T20:29:23Z", "hours": 1.95, "text": "MORE TORQUE LEG DESIGN BODY CAD! So, it’s the body for the more torque leg design, for now it’s the can say the basis structure and then will later on make triangular pockets on walls to reduce weight and weight and remain rigid and will also add holes for screws and supports also. Subscribe YouTube Instagram"}, {"post_id": 45327, "ts": "2026-08-11T18:27:55Z", "hours": 1.2833, "text": "THE FINAL BODY DESIGN FOR MORE TORQUE LEG HEXAPOD/SPIDER ROBOT 2.0! So, the first one was too wide then tried making it less wider but then thought there should be more space for wires and maybe air flow also for those converters. So, in the 3rd one increased a few 2-3centemeters and its all good now and have space for other small things also if needed. And do we need to record timelapse when we post the ship? Subscribe YouTube Instagram"}, {"post_id": 44784, "ts": "2026-08-10T19:54:45Z", "hours": 3.05, "text": "BODY DESIGN! Came up with this body design, maybe will change it later on if needed for now it can fit battery and converters and drivers, maybe will increase width later on to get flexibility in batter space. Subscribe YouTube Instagram"}, {"post_id": 44215, "ts": "2026-08-09T20:35:50Z", "hours": 1.8, "text": "Body trying to figure out what components will be there in body and what will be the size of body Subscribe YouTube Instagram"}, {"post_id": 43636, "ts": "2026-08-09T00:33:23Z", "hours": 3.1136, "text": "STL FILES. Made all STL files and did fillet wherever I was able to and realized that I forgot to make screw holes, and all that took more time than expected. Subscribe YouTube Instagram"}, {"post_id": 42867, "ts": "2026-08-07T20:29:59Z", "hours": 2.0667, "text": "Finally, the more torque leg design is completed now will have to order them and check if everything fits perfectly and will also make the long leg less torque designs. Subscribe YouTube Instagram"}, {"post_id": 42211, "ts": "2026-08-06T20:29:18Z", "hours": 4.7772, "text": "TIBIA 75% COMPLETE! Now will check all the things and maybe order the whole leg and will also start making another design. Subscribe YouTube Instagram"}, {"post_id": 41523, "ts": "2026-08-05T19:41:57Z", "hours": 4.6669, "text": "THE MOST TORQUE FEMUR PART. So, made the most torque femur part and will make the most torque tibia part. Subscribe YouTube Instagram"}, {"post_id": 40929, "ts": "2026-08-04T19:28:17Z", "hours": 3.6836, "text": "COXA HORN TO FEMUR PART Made the coca horn to femur part and will make femur horn to tibia motor part and the whole tibia. Subscribe YouTube Instagram"}, {"post_id": 40307, "ts": "2026-08-03T18:57:39Z", "hours": 3.6608, "text": "COXA PART AND SOME MORE THINGS! Made the coxa part and also did some corrections and made some more options for trial. Subscribe YouTube Instagram"}, {"post_id": 39676, "ts": "2026-08-02T20:13:05Z", "hours": 6.4581, "text": "GROUND SENSOR / SHOCK ABSORBER! So, finally the ground sensor/shock absorber CAD files are completed it has 6 parts it’s very complex and still have to make some more shock absorber designs with another dimensions and will be checking everything and will also start designing leg parts. Subscribe YouTube Instagram"}, {"post_id": 38168, "ts": "2026-07-31T12:56:57Z", "hours": 1.4689, "text": "GROUND SENSOR / SHOCK ABSORBER! So, started CAD designing the shock absorber / ground sensor build more then half of it, will complete it after measuring few things which I forgot to measure earlier. Subscribe YouTube Instagram"}, {"post_id": 36259, "ts": "2026-07-28T07:46:59Z", "hours": 3.2517, "text": "Finally, the ground/shock absorber sensor design is completed now will start making all the CAD and will check if anything’s left. Subscribe YouTube Instagram"}, {"post_id": 35947, "ts": "2026-07-27T18:37:34Z", "hours": 0.6167, "text": "The ground sensor and shock absorber sensor design is almost done just have to find right length and thickness of shock absorber. Subscribe YouTube Instagram"}, {"post_id": 35394, "ts": "2026-07-26T19:18:29Z", "hours": 3.8019, "text": "Tibia design fixed again and designing ground sensor and shock absorber! Okay so I fixed the tibia design as the last one was too curved and also, I will be adding a shock absorber so that the gears won’t break! Till now 20% of the shock absorber’s design is made. Subscribe YouTube Instagram"}, {"post_id": 34816, "ts": "2026-07-25T20:27:23Z", "hours": 6.9781, "text": "High torque design done! So was finally able to figure out the designs and made the height torque design, so in this High torque design the femur and tibia are as short as possible so that it gets maximum torque. Now will start CAD and will also make the less torque/long leg design. Subscribe YouTube Instagram"}, {"post_id": 34242, "ts": "2026-07-24T19:33:49Z", "hours": 2.7333, "text": "COXA AND FEMUR DESIGN READY! The fixed design of coxa and femur is ready and now will make tibia and then will start CAD! Subscribe YouTube Instagram"}, {"post_id": 33166, "ts": "2026-07-22T20:33:50Z", "hours": 3.1508, "text": "Redesigned the part! Finally redesigned the femur horn to tibia servo part including the servo bottom cover chassis and will have to redesign the femur to coxa part too, and I made this simple mechanism too as I wanted to test something. Subscribe YouTube Instagram"}, {"post_id": 32622, "ts": "2026-07-21T22:10:45Z", "hours": 3.3503, "text": "Ohhh nooo made a mistake!! Hexapod 2.0! So, I forgot to measure the bottom wall thickness which will be covering servo and will be having ball bearings and now I will have to redesign the (Femur servo to Coxa horn) part and the new part I was making which will connect Femur horn to Tibia servo. And I deleted all the previous cad files for Hexapod 2.0 as they were all without that bottom wall measurement. Subscribe YouTube Instagram"}, {"post_id": 31965, "ts": "2026-07-20T19:47:55Z", "hours": 0.7669, "text": "DESIGNING FEMUR HORN TO TIBIA MOTOR PART FOR HEXAPOD 2.O! So, I’m trying to figure out things like how I would connect the motors to each other as due to angle and other things the lengths changes and I’m thinking of making a different type of tibia or maybe a modular tibia. but for now, I will try to complete the femur to tibia motor chassis. Subscribe YouTube Instagram"}, {"post_id": 31409, "ts": "2026-07-19T19:05:44Z", "hours": 3.6672, "text": "NEW FEMUR MOTOR CHASSIS DESIGN FOR HEXAPOD/SPIDER ROBOT 2.0! Okay so, I did modifications in the femur motor chassis design as I forgot to make holes for servo mounting screws so had to change both upper parts chassis designs. Maybe I’ll change the lower chassis design later if I can find a better alternative for the ball bearings. Subscribe YouTube Instagram"}, {"post_id": 31084, "ts": "2026-07-19T06:17:15Z", "hours": 1.0336, "text": "FINAL PART of femur motor chassis! This is the final part which we need for the femur motor chassis, now after this tibia and coxa. Subscribe YouTube Instagram"}, {"post_id": 31034, "ts": "2026-07-19T03:05:01Z", "hours": 0.7339, "text": "Femur servo chassis first upper part! This part will hold the horn of the coxa servo and will attach it to the previous part which holds femur motor by using M3 screws. subscribe youtube- ( https://youtube.com/@protoshredhq?si=L7gl_OnR4_PLbjfH ), Instagram-( https://www.youtube.com/redirect?event=channel_description&redir_token=QUM4Zm9rU01VRHlzdEpObzc1cG1MNXZxd3lXcnxBR3JiS2FrQ0NJdkNObFBtSFVJUXpPRXBOM1Z3N2JtZ181SWFDV09SV0JkejcwQklVY0lwU0tyWWs4OWJnU3BUV3dnMVFZZ09lcFNYTjYzM3oyOVJ6QnlCUXZJczNJSjRhWVBO&q=https%3A%2F%2Fwww.instagram.com%2Fprotoshred_hq%3Figsh%3DMThsc2F6azVmeXNrZA%3D%3D )"}, {"post_id": 30927, "ts": "2026-07-18T22:29:19Z", "hours": 2.8514, "text": "HEXAPOD/SPIDER ROBOT FEMUR MOTOR PART! Made the lower piece of the femur motor chassis, each leg part is in 2-3 pieces. this one holds the motor and ball bearing hold bracket for coxa motor piece and a socket to fit ball bearing for tibia motor piece. Subscribe YouTube Instagram"}, {"post_id": 30617, "ts": "2026-07-18T10:35:27Z", "hours": 4.6428, "text": "LEG FOR BIG HEXAPOD/SPIDER ROBOT! So, I made parts for coxa servo and femur servo, the upper one will attach coxa servo to body, and the lower one will attach femur servo to coxa servo horn. and this time I will be using ID=8mm, OD=22mm, W=7 mm ball bearings. Subscribe YouTube Instagram"}, {"post_id": 29844, "ts": "2026-07-17T00:02:58Z", "hours": 3.4822, "text": "HEXAPOD/SPIDER ROBOT 2.0! So, this will be the larger version of the hexapod/spider robot, in this version I will be using mg996r motors instead of mg90s motors. I noted all dimensions of the servo and the circular horn and now will start making the leg designs. Subscribe YouTube Instagram"}]...
|
Title: HEXAPOD/SPIDER ROBOT 2.O by @Vedaprotoshred Title: HEXAPOD/SPIDER ROBOT 2.O by @Vedaprotoshredhq | Stardance
Devlogs:
HEXAPOD/SPIDER ROBOT 2.0! So, this will be the larger version of the hexapod/spider robot, in this version I will be using mg996r motors instead of mg90s motors. I noted all dimensions of the servo and the circular horn and now will start making the leg designs. Subscribe YouTube Instagram
LEG FOR BIG HEXAPOD/SPIDER ROBOT! So, I made parts for coxa servo and femur servo, the upper one will attach coxa servo to body, and the lower one will attach femur servo to coxa servo horn. and this time I will be using ID=8mm, OD=22mm, W=7 mm ball bearings. Subscribe YouTube Instagram
HEXAPOD/SPIDER ROBOT FEMUR MOTOR PART! Made the lower piece of the femur motor chassis, each leg part is in 2-3 pieces. this one holds the motor and ball bearing hold bracket for coxa motor piece and a socket to fit ball bearing for tibia motor piece. Subscribe YouTube Instagram
Femur servo chassis first upper part! This part will hold the horn of the coxa servo and will attach it to the previous part which holds femur motor by using M3 screws. subscribe youtube- ( https://youtube.com/@protoshredhq?si=L7gl_OnR4_PLbjfH ), Instagram-( https://www.youtube.com/redirect?event=channel_description&redir_token=QUM4Zm9rU01VRHlzdEpObzc1cG1MNXZxd3lXcnxBR3JiS2FrQ0NJdkNObFBtSFVJUXpPRXBOM1Z3N2JtZ181SWFDV09SV0JkejcwQklVY0lwU0tyWWs4OWJnU3BUV3dnMVFZZ09lcFNYTjYzM3oyOVJ6QnlCUXZJczNJSjRhWVBO&q=https%3A%2F%2Fwww.instagram.com%2Fprotoshred_hq%3Figsh%3DMThsc2F6azVmeXNrZA%3D%3D )
FINAL PART of femur motor chassis! This is the final part which we need for the femur motor chassis, now after this tibia and coxa. Subscribe YouTube Instagram
NEW FEMUR MOTOR CHASSIS DESIGN FOR HEXAPOD/SPIDER ROBOT 2.0! Okay so, I did modifications in the femur motor chassis design as I forgot to make holes for servo mounting screws so had to change both upper parts chassis designs. Maybe I’ll change the lower chassis design later if I can find a better alternative for the ball bearings. Subscribe YouTube Instagram
DESIGNING FEMUR HORN TO TIBIA MOTOR PART FOR HEXAPOD 2.O! So, I’m trying to figure out things like how I would connect the motors to each other as due to angle and other things the lengths changes and I’m thinking of making a different type of tibia or maybe a modular tibia. but for now, I will try to complete the femur to tibia motor chassis. Subscribe YouTube Instagram
Ohhh nooo made a mistake!! Hexapod 2.0! So, I forgot to measure the bottom wall thickness which will be covering servo and will be having ball bearings and now I will have to redesign the (Femur servo to Coxa horn) part and the new part I was making which will connect Femur horn to Tibia servo. And I deleted all the previous cad files for Hexapod 2.0 as they were all without that bottom wall measurement. Subscribe YouTube Instagram
Redesigned the part! Finally redesigned the femur horn to tibia servo part including the servo bottom cover chassis and will have to redesign the femur to coxa part too, and I made this simple mechanism too as I wanted to test something. Subscribe YouTube Instagram
COXA AND FEMUR DESIGN READY! The fixed design of coxa and femur is ready and now will make tibia and then will start CAD! Subscribe YouTube Instagram
High torque design done! So was finally able to figure out the designs and made the height torque design, so in this High torque design the femur and tibia are as short as possible so that it gets maximum torque. Now will start CAD and will also make the less torque/long leg design. Subscribe YouTube Instagram
Tibia design fixed again and designing ground sensor and shock absorber! Okay so I fixed the tibia design as the last one was too curved and also, I will be adding a shock absorber so that the gears won’t break! Till now 20% of the shock absorber’s design is made. Subscribe YouTube Instagram
The ground sensor and shock absorber sensor design is almost done just have to find right length and thickness of shock absorber. Subscribe YouTube Instagram
Finally, the ground/shock absorber sensor design is completed now will start making all the CAD and will check if anything’s left. Subscribe YouTube Instagram
GROUND SENSOR / SHOCK ABSORBER! So, started CAD designing the shock absorber / ground sensor build more then half of it, will complete it after measuring few things which I forgot to measure earlier. Subscribe YouTube Instagram
GROUND SENSOR / SHOCK ABSORBER! So, finally the ground sensor/shock absorber CAD files are completed it has 6 parts it’s very complex and still have to make some more shock absorber designs with another dimensions and will be checking everything and will also start designing leg parts. Subscribe YouTube Instagram
COXA PART AND SOME MORE THINGS! Made the coxa part and also did some corrections and made some more options for trial. Subscribe YouTube Instagram
COXA HORN TO FEMUR PART Made the coca horn to femur part and will make femur horn to tibia motor part and the whole tibia. Subscribe YouTube Instagram
THE MOST TORQUE FEMUR PART. So, made the most torque femur part and will make the most torque tibia part. Subscribe YouTube Instagram
TIBIA 75% COMPLETE! Now will check all the things and maybe order the whole leg and will also start making another design. Subscribe YouTube Instagram
Finally, the more torque leg design is completed now will have to order them and check if everything fits perfectly and will also make the long leg less torque designs. Subscribe YouTube Instagram
STL FILES. Made all STL files and did fillet wherever I was able to and realized that I forgot to make screw holes, and all that took more time than expected. Subscribe YouTube Instagram
Body trying to figure out what components will be there in body and what will be the size of body Subscribe YouTube Instagram
BODY DESIGN! Came up with this body design, maybe will change it later on if needed for now it can fit battery and converters and drivers, maybe will increase width later on to get flexibility in batter space. Subscribe YouTube Instagram
THE FINAL BODY DESIGN FOR MORE TORQUE LEG HEXAPOD/SPIDER ROBOT 2.0! So, the first one was too wide then tried making it less wider but then thought there should be more space for wires and maybe air flow also for those converters. So, in the 3rd one increased a few 2-3centemeters and its all good now and have space for other small things also if needed. And do we need to record timelapse when we post the ship? Subscribe YouTube Instagram
MORE TORQUE LEG DESIGN BODY CAD! So, it’s the body for the more torque leg design, for now it’s the can say the basis structure and then will later on make triangular pockets on walls to reduce weight and weight and remain rigid and will also add holes for screws and supports also. Subscribe YouTube Instagram
😭😭divided into in 1/4th and did a lot of work, made coxa part brackets and made a lot of triangles for the triangular structure like bottom and then later on realised that it’s center is not on origin so it was all waste and will have to made the whole body from scratch again😭😭 Subscribe YouTube Instagram
MORE TORQUE LEG BODY DESIGN! So, made the whole body again and made it at origin this time and now was trying to make the spider web kind of structure for the bottom layer and it’s all so much messed up, but I think I will be able to do it so will try. Subscribe YouTube Instagram
FINALL! BODY FOR THE HEXAPOD 2.0 MORE TORQUE LEGS! So, finally after 3-4 tries body for the mg996r servo with more torque leg version is completed as I wrote in previous devlog i tried to make spider net kind of bottom bed and made windows and x shape windows so that it can have less weight and good strength. Subscribe YouTube Instagram
1ST TEST LEG And MISTAKES! So, i finally got the first test leg 3d printed from a local 3d printing service by my own money. I order all the parts of a whole single leg and few different different variants for shock absorber but non of them worked. And also I tried assembling the leg but wasn’t able to as I didn’t had screws for it , and there were few or maybe more then few 😅 mistakes in it ,and some parts need to be improved, so I wrote everything I have to change and also I forgot that I wanted 3-4 exactly same parts in more then 1 quantity so wrote that also, so will now again edit or redesign parts. Subscribe YouTube Instagram
REPAIRING AND UPDATING PARTS. So, like there were few parts which I made wrong and few needs to be upgraded so I didn’t repaired few parts and ungraded this whole part. Subscribe YouTube Instagram
MAKING NEW SHOCK ABSORBER AND REPAIRING PARTS! So, i remade the shock absorber again and after 6 failed variations made another 4 today and repaired few parts and making the new shock absorber took a lot of time. Subscribe YouTube Instagram
A DIFFERENT KIND OF SHOCK ABSORBER AND REBUILD FEMUR PARTS! Okay, so I made a very simple design for the new shock absorber, but I will just be using tpu instead of pla, do I guess that I should work. And rebuild and modified all femur parts as they were all short in length. And made go through space for servo wires in body and tibia. Subscribe YouTube Instagram
ASSEMBLING PARTS! Okay so, I assembled parts, like I tried assembling parts in pieces, Like body to coxa motor then coxa motor horn to femur then femur motor horn to tibia then tibia motor horn to leg and then leg to ground shock sensor. Like I will try to make a complete assembly but maybe my laptop won’t be able to handle it. But still, I will try complete assembly if possible. Subscribe YouTube Instagram...
|
1792788459.9214933
|
1793393259.9214933
|
|
9316
|
OMNI-Chess by @thestarviper | Stardance
|
thestarviper
|
2
|
102.0
|
1511
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-02T01:14:49Z", "hours": 63.0, "multiplier": 17.79, "payout": 873, "blessing": "neutral", "text": "I made a chess engine in raylib with puzzle functionality and a movelog with a nature theme. Migrating from pygame to raylib was a big challenge that took me a while to fix all the kinks. idk the leaves are hoverable for a cool fidget thing and have fun!", "repo": "https://github.com/TheStarViper/chess-eng", "demo": "https://thestarviper.itch.io/chess-engine"}, {"ship_num": 2, "ts": "2026-06-15T03:47:41Z", "hours": 39.0, "multiplier": 16.63, "payout": 638, "blessing": "neutral", "text": "I made a chess game where you locally 1v1 someone with a move log to see move history and all the special rules/draw conditions like 50 move rule, 3 fold, insufficient material, castling, enpessent. It was challenging doing the historical move rendering because you have to keep track of all the previous board positions and the checks and square highlights Im proud of the move log because its cool yall should know that it’s low res cuz it’s not that efficient and uses pygame and am working on a re-release utilizing raylib for more proformance", "repo": "https://github.com/TheStarViper/chess-eng", "demo": "https://thestarviper.itch.io/chess-engine"}]...
|
[{"post_id": 20435, "ts": "202 [{"post_id": 20435, "ts": "2026-07-02T00:59:11Z", "hours": 4.7919, "text": "UPDATE #13 This is the last update before i ship So basically this was just the last update for this project cuz i decided i would start work on a different project, the changes i made this update are just to get ready to ship and complete the project: removed fps counter removed openings and play menu removed variants from selection as they arent polished enough removed misc debug features audio bug fixed on button hovers audio bug fixed on puzzle win"}, {"post_id": 17944, "ts": "2026-06-28T22:04:11Z", "hours": 17.1667, "text": "UPDATE #12 added features added variants support added giveaway chess added duckchess (kinda) added the start of a play screen, still working on it not much yet added easing functions to some visuals so they appear instead of popping in fixed bugs/cleanup (like 50% of this devlog) split code back into multiple files fixed that puzzle code was directly in frame update loop tons of crash fixes todo with variants and puzzles animation broke on variants draw legal moves didn’t work on custom pieces future ideas clock bots particle system effects screen shake randomize leaves menu transitions i was mainly struggling to fix crash bugs this devlog as there were multiple that i had to fix, most notably there was a crash bug when swapping between the game and puzzle menus, and loading a new ruleset for variants. My current plan now is to finish the create game screen, then work on fixing the last duckchess bugs, programming a bot then variants + polish. I may ship again if i get a chance before i finish this though. Screenshot here shots duckchess in action but I made the duck sprite using AI just so we’re clear about that because i am bad at art."}, {"post_id": 15352, "ts": "2026-06-24T23:25:28Z", "hours": 9.0172, "text": "Update #11 Added Features added puzzle side menu added puzzle streak counter skip retry hint puzzle buttons sucess rate puzzle counter sound effect for hovering button puzzles are basically done Fixed Bugs 3 fold occured in puzzle mode if you made the same wrong move 3 times same thing with 50 move rule as 3 fold puzzle would start with you instead of the computer swaps turn on failed move animations didn’t work in puzzles fixed you can select the opponent’s pieces in the puzzle during animation if you hit a frameperfect from the animation finishing on the puzzle screen and switch to the game screen it moves the piece in the game screen if there was a piece on the starting tile same bug with next puzzle button leaves sfx looped infinitely Smart Bool I added a new datatype to make my life easier called a smartbool, this is basically a boolean with a third state called NewTrue which is only true for the first cycle the boolean is updated to true. This boolean is useful for when you want to play a sound effect on hover but if you use a traditional boolean it will play every frame. you can use it like a normal boolean too like smartbool = true; or if (smartbool){} . But this new datatype makes the code easier to understand for me. struct smartbool { enum State { False, NewTrue, True }; State state = False; void operator=(bool value) {this->set(value);} operator bool() const {return state != False; } bool is_new_true() const { return state == NewTrue; } void set(bool value) { if (value) { if (state == False) state = NewTrue; } else { state = False; } } void update() { if (state == NewTrue) { state = True; } } }; Future Ideas clock bots variants more moving graphics/sfx randomize leaves on borders menu transitions (maybe) finish polishing puzzles (pretty much done)"}, {"post_id": 13961, "ts": "2026-06-22T22:21:46Z", "hours": 16.5194, "text": "UPDATE #10 added features/changes added a sidebar added a settings page with the ability to toggle 50 move counter,3 fold counter,board markings with more settings to come like high contrast and animation speed added a makefile to compile code to test instead of running a bunch of commands back to back added puzzles to the puzzle tab pulls random puzzle out of a csv things before next ship more sfx click and drag to move piece sfx plays infinitely on hovers randomize leaves placements menu transitions polish puzzles page and get rid of bugs general ideas theme switcher animation speed control move clock In this update i messed up my codebase so massively bad trying to refactor the code so alot of my time was fixing the nuke i dropped into my codebase. uhhh one of the big bugs i had to squash before this that took eternity was playing sound effects would just crash the game. It turned out the reason was i didnt add the compile flag to my makefile causing the audio mixer to crash the game. After that i added sound effects back in and then started to work on puzzles. for puzzles i took the lichess puzzle database of 6m puzzles and condensed it down to 100k for file space. I pull a random row from this file to create the puzzle and it kinda works but its still in progress."}, {"post_id": 11768, "ts": "2026-06-19T04:42:16Z", "hours": 7.4614, "text": "UPDATE #9 I presented my changes in the stardance slack and was able to get some new ideas like adding a theme switcher. I added the leaves cuz i thought it would add to the theme and then after seeing the leaves, they looked very interactable so i made them interactable. idk thats about it changes/added features leaves on outside of board leaves enlarge on hover for fidgeting i guess idk its fun tho made move log more narrow to fit a sidebar on the left added a 3 fold repetition warning that appears after 2x repetition (make togglable) added a background i got from itchio made hover dots enlarge on hover again fixed animation issues changed board markers to inside the board like originally in python updated itchio page things before next ship add sound effects back click and drag to move piece add sidebar"}, {"post_id": 10951, "ts": "2026-06-17T23:23:52Z", "hours": 7.9317, "text": "UPDATE #8 This version is not live yet as there are a few bugs that need fixing still as the port from python introduced alot. Some things i liked about porting from python to c++ is that i was able to fine tune things more and use namespaces which i like. ENUMs are also a feature i like. changes/added features Updated graphics to use pieces from itchio 50 move rule counter under game log (i plan to make it togglable) says whos turn it is to play in top right ontop of the highlighting changed entire game to pixelart because i found some assets on itchio that i thought looked really nice things needed for next ship going to add a sidebar on the left side instead of the right side add sound effects back add a background click and drag to move piece animation issues fold repetition counter under move log make itchio page look better next devlog should be when i update the itchio page and other stuff also i spent closer to 15-16 hours on this cuz it includes the last devlog"}, {"post_id": 9054, "ts": "2026-06-15T03:36:13Z", "hours": 8.3464, "text": "UPDATE #7 i wanna have the time logged for shipping but basically all i did was change some file formats for web assembly and turned down the resolution so that it would automatically scale so that it’s playable. I’m currently in the process of converting the game from pygame to c++ raylib since i know c++ already and c++ is better for WASM thats about ittttttttt live ver: https://thestarviper.itch.io/chess-engine"}, {"post_id": 7870, "ts": "2026-06-13T03:53:24Z", "hours": 8.3592, "text": "UPDATE #6 fixed bugs: all game end conditions were broken move log scrollbar didn’t appear on pawn promotion move log didnt use proper notation canceling pawn promotion didnt undo move log canceling pawn promotion capture didnt undo capture when going back in move log, if there was a check the square didnt light red couldn’t change piece to move after selecting a piece added features/changes: promotion menu is inline column added sfx better sprites for pieces draw and resign buttons now use icons move log text now uses the Audiowide regular fond massive code restructure things needed for shipping: optimization, didn’t optimize since last devlog maybe learn WHAT DA HAIL bitboards are to optimize yk click and drag to move piece pieces flicker for a frame when transitioning from animation to static on the board"}, {"post_id": 6680, "ts": "2026-06-11T05:52:38Z", "hours": 3.0944, "text": "UPDATE #5 fixed bugs: checkmate didnt work (again) when king is in check the square didnt light red move log overflowed when filling up so i added a scroll feature added features/changes: promotion gui is now like chess.com and vertical move log is striped and alternates colors for each row board markings for the rows and columns things needed before shipping: optimization, still runs at like 45fps on itch.io sound effects maybe change fonts cuz im using default ugly ones draw/resign icons instead of text click and drag to move piece better sprites for pieces (BUG) can’t move a different piece after selecting one (BUG) draw conditions are broken (BUG) sidebar buttons are broken even though they dont do anything (BUG) when looking back in the move log when the king is in check the square stays red"}, {"post_id": 6058, "ts": "2026-06-10T05:41:11Z", "hours": 5.0128, "text": "UPDATE #4 I fixed preformance :D heres how: i drew the move log table 3x per frame instead of once so i made it do it once now was calculating if someone was in checkmate every frame which was checking if anyone had legal moves every single frame, changed it to check for checkmate on clicks which is every time someone made a move some of the stuff we were rendering were static background elements that never changed and they were being drawn every frame. So instead we render them once at the start and cache it so that we don’t render static elements so many times. (i accidentally changed the opacity of the background and dont feel like retaking the screenshot and accidentally moved the sidebar) FPS my machine 30-40 -> 200+ FPS itch.io 10 -> 45 we still have a ways to go to get a fully smooth experience but 10 to 45 fps from the demo link is much much more playable and i thought i would get a devlog out. next update ill continue to optimize and polish to get ready to ship!"}, {"post_id": 5727, "ts": "2026-06-09T17:02:19Z", "hours": 3.425, "text": "UPDATE #3 things added in this update: added a subtle background added a sidebar added “Game Log” text moved board and bar to the right a bit added a GitHub readme rounded corners of chess board and other stuff Issues: I started to notice the rendering of my chess pieces moving were slightly lagging, after doing a performance test of my code using python’s profile tool i noticed that my logic for getting legal moves was called 160k+ times and my pieces were rendered 50k+ times. This made my chess engine run at 30-50 fps so i will have to fix the performance issues soon. Next update will prolly be addressing these issues and adding more UI changes"}, {"post_id": 5349, "ts": "2026-06-09T02:49:21Z", "hours": 2.9911, "text": "UPDATE #2 things added in this update: created an itch.io page to demo the game by compiled the PYgame with pygbag added a move log with the ability to look back in time legal move dots now enlarge on hover i plan on actually making the itch.io page look good and actually add a readme to my github repo that looks good but i plan on doing that later. next update i think will be gui changes then after that i will work on QOL changes then feature additions like variants Fully functional game though and i did work on my laptop without wakatime so sad it wasnt tracked :c"}, {"post_id": 4605, "ts": "2026-06-07T23:34:09Z", "hours": 7.4347, "text": "UPDATE #1 I have created using pygame a chess engine complete with all of the rules of chess and is fully playable for local 1v1 with the features: on piece hover, piece tilts a bit piece moves to next square instead of teleporting checkmate resign and draw buttons stalemate 3 fold repetition 50 move rule en pessant castling captured pieces are shown on the side that captured them captured piece zone is aligned to board pawn promotion FUTURE IDEAS: SFX Better GUI on loss/draw screens Better GUI for promotion Main menu variants (atomic,duckchess,giveaway chess, Horde, etc) time control bots (pinging chess.com api idk how to code a chess bot from scratch) color change of boards better graphics for pieces move log when hovering on dot of the move you want to make the dot becomes bigge pull and drag pieces around board to make moves like chess.com"}]...
|
Title: OMNI-Chess by @thestarviper | Stardance
De Title: OMNI-Chess by @thestarviper | Stardance
Devlogs:
UPDATE #1 I have created using pygame a chess engine complete with all of the rules of chess and is fully playable for local 1v1 with the features: on piece hover, piece tilts a bit piece moves to next square instead of teleporting checkmate resign and draw buttons stalemate 3 fold repetition 50 move rule en pessant castling captured pieces are shown on the side that captured them captured piece zone is aligned to board pawn promotion FUTURE IDEAS: SFX Better GUI on loss/draw screens Better GUI for promotion Main menu variants (atomic,duckchess,giveaway chess, Horde, etc) time control bots (pinging chess.com api idk how to code a chess bot from scratch) color change of boards better graphics for pieces move log when hovering on dot of the move you want to make the dot becomes bigge pull and drag pieces around board to make moves like chess.com
UPDATE #2 things added in this update: created an itch.io page to demo the game by compiled the PYgame with pygbag added a move log with the ability to look back in time legal move dots now enlarge on hover i plan on actually making the itch.io page look good and actually add a readme to my github repo that looks good but i plan on doing that later. next update i think will be gui changes then after that i will work on QOL changes then feature additions like variants Fully functional game though and i did work on my laptop without wakatime so sad it wasnt tracked :c
UPDATE #3 things added in this update: added a subtle background added a sidebar added “Game Log” text moved board and bar to the right a bit added a GitHub readme rounded corners of chess board and other stuff Issues: I started to notice the rendering of my chess pieces moving were slightly lagging, after doing a performance test of my code using python’s profile tool i noticed that my logic for getting legal moves was called 160k+ times and my pieces were rendered 50k+ times. This made my chess engine run at 30-50 fps so i will have to fix the performance issues soon. Next update will prolly be addressing these issues and adding more UI changes
UPDATE #4 I fixed preformance :D heres how: i drew the move log table 3x per frame instead of once so i made it do it once now was calculating if someone was in checkmate every frame which was checking if anyone had legal moves every single frame, changed it to check for checkmate on clicks which is every time someone made a move some of the stuff we were rendering were static background elements that never changed and they were being drawn every frame. So instead we render them once at the start and cache it so that we don’t render static elements so many times. (i accidentally changed the opacity of the background and dont feel like retaking the screenshot and accidentally moved the sidebar) FPS my machine 30-40 -> 200+ FPS itch.io 10 -> 45 we still have a ways to go to get a fully smooth experience but 10 to 45 fps from the demo link is much much more playable and i thought i would get a devlog out. next update ill continue to optimize and polish to get ready to ship!
UPDATE #5 fixed bugs: checkmate didnt work (again) when king is in check the square didnt light red move log overflowed when filling up so i added a scroll feature added features/changes: promotion gui is now like chess.com and vertical move log is striped and alternates colors for each row board markings for the rows and columns things needed before shipping: optimization, still runs at like 45fps on itch.io sound effects maybe change fonts cuz im using default ugly ones draw/resign icons instead of text click and drag to move piece better sprites for pieces (BUG) can’t move a different piece after selecting one (BUG) draw conditions are broken (BUG) sidebar buttons are broken even though they dont do anything (BUG) when looking back in the move log when the king is in check the square stays red
UPDATE #6 fixed bugs: all game end conditions were broken move log scrollbar didn’t appear on pawn promotion move log didnt use proper notation canceling pawn promotion didnt undo move log canceling pawn promotion capture didnt undo capture when going back in move log, if there was a check the square didnt light red couldn’t change piece to move after selecting a piece added features/changes: promotion menu is inline column added sfx better sprites for pieces draw and resign buttons now use icons move log text now uses the Audiowide regular fond massive code restructure things needed for shipping: optimization, didn’t optimize since last devlog maybe learn WHAT DA HAIL bitboards are to optimize yk click and drag to move piece pieces flicker for a frame when transitioning from animation to static on the board
UPDATE #7 i wanna have the time logged for shipping but basically all i did was change some file formats for web assembly and turned down the resolution so that it would automatically scale so that it’s playable. I’m currently in the process of converting the game from pygame to c++ raylib since i know c++ already and c++ is better for WASM thats about ittttttttt live ver: https://thestarviper.itch.io/chess-engine
UPDATE #8 This version is not live yet as there are a few bugs that need fixing still as the port from python introduced alot. Some things i liked about porting from python to c++ is that i was able to fine tune things more and use namespaces which i like. ENUMs are also a feature i like. changes/added features Updated graphics to use pieces from itchio 50 move rule counter under game log (i plan to make it togglable) says whos turn it is to play in top right ontop of the highlighting changed entire game to pixelart because i found some assets on itchio that i thought looked really nice things needed for next ship going to add a sidebar on the left side instead of the right side add sound effects back add a background click and drag to move piece animation issues fold repetition counter under move log make itchio page look better next devlog should be when i update the itchio page and other stuff also i spent closer to 15-16 hours on this cuz it includes the last devlog
UPDATE #9 I presented my changes in the stardance slack and was able to get some new ideas like adding a theme switcher. I added the leaves cuz i thought it would add to the theme and then after seeing the leaves, they looked very interactable so i made them interactable. idk thats about it changes/added features leaves on outside of board leaves enlarge on hover for fidgeting i guess idk its fun tho made move log more narrow to fit a sidebar on the left added a 3 fold repetition warning that appears after 2x repetition (make togglable) added a background i got from itchio made hover dots enlarge on hover again fixed animation issues changed board markers to inside the board like originally in python updated itchio page things before next ship add sound effects back click and drag to move piece add sidebar
UPDATE #10 added features/changes added a sidebar added a settings page with the ability to toggle 50 move counter,3 fold counter,board markings with more settings to come like high contrast and animation speed added a makefile to compile code to test instead of running a bunch of commands back to back added puzzles to the puzzle tab pulls random puzzle out of a csv things before next ship more sfx click and drag to move piece sfx plays infinitely on hovers randomize leaves placements menu transitions polish puzzles page and get rid of bugs general ideas theme switcher animation speed control move clock In this update i messed up my codebase so massively bad trying to refactor the code so alot of my time was fixing the nuke i dropped into my codebase. uhhh one of the big bugs i had to squash before this that took eternity was playing sound effects would just crash the game. It turned out the reason was i didnt add the compile flag to my makefile causing the audio mixer to crash the game. After that i added sound effects back in and then started to work on puzzles. for puzzles i took the lichess puzzle database of 6m puzzles and condensed it down to 100k for file space. I pull a random row from this file to create the puzzle and it kinda works but its still in progress.
Update #11 Added Features added puzzle side menu added puzzle streak counter skip retry hint puzzle buttons sucess rate puzzle counter sound effect for hovering button puzzles are basically done Fixed Bugs 3 fold occured in puzzle mode if you made the same wrong move 3 times same thing with 50 move rule as 3 fold puzzle would start with you instead of the computer swaps turn on failed move animations didn’t work in puzzles fixed you can select the opponent’s pieces in the puzzle during animation if you hit a frameperfect from the animation finishing on the puzzle screen and switch to the game screen it moves the piece in the game screen if there was a piece on the starting tile same bug with next puzzle button leaves sfx looped infinitely Smart Bool I added a new datatype to make my life easier called a smartbool, this is basically a boolean with a third state called NewTrue which is only true for the first cycle the boolean is updated to true. This boolean is useful for when you want to play a sound effect on hover but if you use a traditional boolean it will play every frame. you can use it like a normal boolean too like smartbool = true; or if (smartbool){} . But this new datatype makes the code easier to understand for me. struct smartbool { enum State { False, NewTrue, True }; State state = False; void operator=(bool value) {this->set(value);} operator bool() const {return state != False; } bool is_new_true() const { return state == NewTrue; } void set(bool value) { if (value) { if (state == False) state = NewTrue; } else { state = False; } } void update() { if (state == NewTrue) { state = True; } } }; Future Ideas clock bots variants more moving graphics/sfx randomize leaves on borders menu transitions (maybe) finish polishing puzzles (pretty much done)
UPDATE #12 added features added variants support added giveaway chess added duckchess (kinda) added the start of a play screen, still working on it not much yet added easing functions to some visuals so they appear instead of popping in fixed bugs/cleanup (like 50% of this devlog) split code back into multiple files fixed that puzzle code was directly in frame update loop tons of crash fixes todo with variants and puzzles animation broke on variants draw legal moves didn’t work on custom pieces future ideas clock bots particle system effects screen shake randomize leaves menu transitions i was mainly struggling to fix crash bugs this devlog as there were multiple that i had to fix, most notably there was a crash bug when swapping between the game and puzzle menus, and loading a new ruleset for variants. My current plan now is to finish the create game screen, then work on fixing the last duckchess bugs, programming a bot then variants + polish. I may ship again if i get a chance before i finish this though. Screenshot here shots duckchess in action but I made the duck sprite using AI just so we’re clear about that because i am bad at art.
UPDATE #13 This is the last update before i ship So basically this was just the last update for this project cuz i decided i would start work on a different project, the changes i made this update are just to get ready to ship and complete the project: removed fps counter removed openings and play menu removed variants from selection as they arent polished enough removed misc debug features audio bug fixed on button hovers audio bug fixed on puzzle win
Ships:
I made a chess game where you locally 1v1 someone with a move log to see move history and all the special rules/draw conditions like 50 move rule, 3 fold, insufficient material, castling, enpessent. It was challenging doing the historical move rendering because you have to keep track of all the previous board positions and the checks and square highlights Im proud of the move log because its cool yall should know that it’s low res cuz it’s not that efficient and uses pygame and am working on a re-release utilizing raylib for more proformance
I made a chess engine in raylib with puzzle functionality and a movelog with a nature theme. Migrating from pygame to raylib was a big challenge that took me a while to fix all the kinks. idk the leaves are hoverable for a cool fidget thing and have fun!...
|
1792983320.135912
|
1793069720.135912
|
|
18350
|
twig by @anshulm1669 | Stardance
|
anshulm1669
|
0
|
101.99
|
0
|
[]
|
[{"post_id": 47800, "ts": "202 [{"post_id": 47800, "ts": "2026-08-16T00:21:41Z", "hours": 10.2053, "text": "Documentation and fixing minor things"}, {"post_id": 35504, "ts": "2026-07-26T23:53:25Z", "hours": 10.3725, "text": "will edit later"}, {"post_id": 33259, "ts": "2026-07-23T00:55:51Z", "hours": 10.6828, "text": "This was 50% started in the last devlog but I decided to only write about it here. I ran into a major issue with the github REST API - rate limits. If your project had 200+ files, then it would run into the rate limit for sure. And while I could’ve let this limit stay and make it easier on myself, I decided that I didn’t want to live within this limit, and it was time to look for a new git solution. The solution: isomoprhic-git. Its a library that gives FULL git compatibility and features but its written completely in javascript. The only bummer was that it was a git clone, meaning it created a .git folder and operated out of that. I really dont like the idea of having a .git folder shadow a twig user, because then what is the point of someone using my version control, right? so heres how github pushing/pulling works with twig and isomorphic git. when you use the github push command, twig creates a folder called “twig-engine” within the “.twig” folder and that twig-engine folder is basically a “.git” folder renamed. Then, twig does its needed treeWrite operations in that twig engine folder, pushes it to github, and then deletes the twig engine folder. Basically, it is never seen by the user and only appears when needed."}, {"post_id": 30557, "ts": "2026-07-18T07:16:19Z", "hours": 10.5367, "text": "this coding session is filled with a lot of small different things. I’ve come back to a lot of features and added touch ups / fixes to things I said I would come back later to. Something important is the main bin.js file, which is now approaching 2000 lines of code, is being split up into multiple files to make it easier to understand and for me to debug/make changes. Another thing is that I’ve started the documentation for twig and its commands / how it works."}, {"post_id": 28796, "ts": "2026-07-15T09:20:40Z", "hours": 9.4461, "text": "for the last 10 hours i’ve been trying to make twig compatible with github. but this is much much much harder than i ever thought it would’ve been. the git smart http protocol is how git communicates to any service like github/gitlab etc. The problem for me is this protocol has had 20 years of development and improvement and it is extremely difficult to understand let alone recreate. Github only knows this form of communication (packfiles and delta compression) so I have to find a library that can communicate to github. But it doesn’t get a lot better… there are of course git libraries but none of them are for ONLY uploading / pulling things from github. Furthermore, they are all git clones meaning they operate within a .git folder and they aren’t met to be used as a SDK in another version control client. So, heres what I went with: the github REST API! it lets you create commits / trees / blobs and then push them to repositories. So thats exactly what I used"}, {"post_id": 27453, "ts": "2026-07-13T01:03:19Z", "hours": 12.3458, "text": "Twig can now merge branches with its own merging algorithm. This was a really really hard command to get working. It was ALOT of debugging and trial/error but in the end it works really well and im super proud of it. At the moment, if there is a merge conflict, you have to pick which branch’s changes you want to keep."}, {"post_id": 24532, "ts": "2026-07-08T04:39:20Z", "hours": 23.5617, "text": "So… I kinda forgot to write dev logs because I got extremely carried away with the coding. Once the ideas started coming, I was just adding command after command. So, i’ve decided to write docs for twig so you can see the list of commands AND in the docs will be a much better explanation of how a version control client works because it is pretty hard to understand. I’ll use devlogs just to briefly summarize the progress ive made but not describe how things work etc. twig can have branches now twig can switch between branches with checkout (twig reads the tree for the branches latest commit and automatically adds/deletes/modifies files to match the branches state) twig has a really ugly server page it runs with the GUI command so you can view the projects branches then commits then what the files looked like at that commit in time. login - this is really special. login to my own custom auth server and store a user token. this token will be used to authenticate to my server. push - push your project files to my server so you can access them anywhere. it stores them successfully but i haven’t gotten the view part down yet."}, {"post_id": 16757, "ts": "2026-06-27T06:38:12Z", "hours": 5.5014, "text": "twig now can handle as many commits as you want, and then read them back to you in order with the history command. on top of that, you can compare two commits using their commit hashes (added, deleted, modified) something cool about the compare command is that you can input the commit hashes in any order, not which came first, because twig automatically finds which comes first."}, {"post_id": 10319, "ts": "2026-06-16T23:57:21Z", "hours": 1.3383, "text": "Commits now generate a new tree, and that tree captures the current working directory. If someone commits and only changes one file very close to the root folder (not deep inside folders) then only that root tree is going to change, and the rest of the subfolder trees wont. Also, I am officially renaming this project! I picked chimp because i wanted it to fit the theme with another tool I built that was monkey related. However, it doesnt fit well to me so rename coming soon…"}, {"post_id": 9772, "ts": "2026-06-16T06:40:17Z", "hours": 1.0411, "text": "Added commit feature. It takes a message and hashes any new files or any files with changes made. Next session, I need to make it so it also generates a new tree per commit."}, {"post_id": 9723, "ts": "2026-06-16T04:38:17Z", "hours": 3.1181, "text": "chimp now stores the file tree of which hash is which file in a sqllite database!"}, {"post_id": 9002, "ts": "2026-06-15T00:28:35Z", "hours": 1.6083, "text": "Wrapped up the initialize command: it now follows through the entire directory, all subfolders and files and hashes them. next step is to make a tree map that tells you which hash is what file. For that next step, i spent some time messing around with sqllite which is what i will be using to store that tree map."}, {"post_id": 8493, "ts": "2026-06-14T03:50:03Z", "hours": 2.2314, "text": "The goal: build a version control client just like git. Maybe even a custom website to store users code online? I started with the first command for my “git” clone, which is “init” and then also test hashing + file writing abilities. The name is “chimp”"}]...
|
Title: twig by @anshulm1669 | Stardance
Devlogs:
Title: twig by @anshulm1669 | Stardance
Devlogs:
The goal: build a version control client just like git. Maybe even a custom website to store users code online? I started with the first command for my “git” clone, which is “init” and then also test hashing + file writing abilities. The name is “chimp”
Wrapped up the initialize command: it now follows through the entire directory, all subfolders and files and hashes them. next step is to make a tree map that tells you which hash is what file. For that next step, i spent some time messing around with sqllite which is what i will be using to store that tree map.
chimp now stores the file tree of which hash is which file in a sqllite database!
Added commit feature. It takes a message and hashes any new files or any files with changes made. Next session, I need to make it so it also generates a new tree per commit.
Commits now generate a new tree, and that tree captures the current working directory. If someone commits and only changes one file very close to the root folder (not deep inside folders) then only that root tree is going to change, and the rest of the subfolder trees wont. Also, I am officially renaming this project! I picked chimp because i wanted it to fit the theme with another tool I built that was monkey related. However, it doesnt fit well to me so rename coming soon…
twig now can handle as many commits as you want, and then read them back to you in order with the history command. on top of that, you can compare two commits using their commit hashes (added, deleted, modified) something cool about the compare command is that you can input the commit hashes in any order, not which came first, because twig automatically finds which comes first.
So… I kinda forgot to write dev logs because I got extremely carried away with the coding. Once the ideas started coming, I was just adding command after command. So, i’ve decided to write docs for twig so you can see the list of commands AND in the docs will be a much better explanation of how a version control client works because it is pretty hard to understand. I’ll use devlogs just to briefly summarize the progress ive made but not describe how things work etc. twig can have branches now twig can switch between branches with checkout (twig reads the tree for the branches latest commit and automatically adds/deletes/modifies files to match the branches state) twig has a really ugly server page it runs with the GUI command so you can view the projects branches then commits then what the files looked like at that commit in time. login - this is really special. login to my own custom auth server and store a user token. this token will be used to authenticate to my server. push - push your project files to my server so you can access them anywhere. it stores them successfully but i haven’t gotten the view part down yet.
Twig can now merge branches with its own merging algorithm. This was a really really hard command to get working. It was ALOT of debugging and trial/error but in the end it works really well and im super proud of it. At the moment, if there is a merge conflict, you have to pick which branch’s changes you want to keep.
for the last 10 hours i’ve been trying to make twig compatible with github. but this is much much much harder than i ever thought it would’ve been. the git smart http protocol is how git communicates to any service like github/gitlab etc. The problem for me is this protocol has had 20 years of development and improvement and it is extremely difficult to understand let alone recreate. Github only knows this form of communication (packfiles and delta compression) so I have to find a library that can communicate to github. But it doesn’t get a lot better… there are of course git libraries but none of them are for ONLY uploading / pulling things from github. Furthermore, they are all git clones meaning they operate within a .git folder and they aren’t met to be used as a SDK in another version control client. So, heres what I went with: the github REST API! it lets you create commits / trees / blobs and then push them to repositories. So thats exactly what I used
this coding session is filled with a lot of small different things. I’ve come back to a lot of features and added touch ups / fixes to things I said I would come back later to. Something important is the main bin.js file, which is now approaching 2000 lines of code, is being split up into multiple files to make it easier to understand and for me to debug/make changes. Another thing is that I’ve started the documentation for twig and its commands / how it works.
This was 50% started in the last devlog but I decided to only write about it here. I ran into a major issue with the github REST API - rate limits. If your project had 200+ files, then it would run into the rate limit for sure. And while I could’ve let this limit stay and make it easier on myself, I decided that I didn’t want to live within this limit, and it was time to look for a new git solution. The solution: isomoprhic-git. Its a library that gives FULL git compatibility and features but its written completely in javascript. The only bummer was that it was a git clone, meaning it created a .git folder and operated out of that. I really dont like the idea of having a .git folder shadow a twig user, because then what is the point of someone using my version control, right? so heres how github pushing/pulling works with twig and isomorphic git. when you use the github push command, twig creates a folder called “twig-engine” within the “.twig” folder and that twig-engine folder is basically a “.git” folder renamed. Then, twig does its needed treeWrite operations in that twig engine folder, pushes it to github, and then deletes the twig engine folder. Basically, it is never seen by the user and only appears when needed.
will edit later
Documentation and fixing minor things...
|
1792511368.666198
|
1793116168.666198
|
|
40589
|
DoFresh by @promise | Stardance
|
promise
|
1
|
101.8
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-14T00:30:17Z", "hours": 99.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "What did you make? This is DoFresh, a refreshing task manager that turns consistency into records and graphs! What was challenging? On top of the various bugs that arose on the way to refine and polish various features, one challenge in creating DoFresh was designing and implementing the Track system. Firstly, the logic system surrounding behind user completion and daily refreshing was complex, especially when considering the users didn’t visit the website every day. Secondly, I strove to make graphs and tracking widgets that were self-explanatory and simple but stylish and understandable, and I had to refactor the Track page completely after I changed my data storage system, changing the types of charts and how each was organized. What are you proud of? I’m quite proud of how the website looks, as I’m really artistically untalented and never really got around to learning CSS or aesthetics or color theory. The purple prettiness of DoFresh is really an achievement for me, and I’m especially proud of how much design and UI/UX consideration I learned through this app. Now, when I open websites, I look at how they design their login pages, where they put their collapsible sidebar icons, and what headings they use—sideways, click-collapse, fixed above, sticky—and why. Another thing I’m quite proud of is the AI agent I personalized and implemented in the Chat page. I wired the API call system for Flask, then Django, with many small bugs for both scenarios, connecting the Python backend with HuggingFace’s free models. Then, two days after I began wrapping up and testing the site, HuggingFace removed its free tier altogether. (●__●) Thus I switched to using GroqCloud as a platform, making a new API key, and set to further refining how the bot understood the user’s completion data, programming it to fit DoFresh’s philosophy and purposes. What should people know so they can test your project? You can go into https://dofresh.onrender.com/ and log in with the credentials stardance_tester + stardance_tester (username + pw both) if you want an example with pre-filled data and records! Please note that (free tier) Render takes about ~40 seconds to load and may spin down to inactiveness if you leave it open and untouched.", "repo": "https://github.com/PurpleSummit/DoFresh", "demo": "https://dofresh.vercel.app"}]...
|
[{"post_id": 81668, "ts": "202 [{"post_id": 81668, "ts": "2026-10-22T00:01:39Z", "hours": 0.8292, "text": "added a custom user creation form to enable flexibility and clean error messages when signing up; debugged the sign-up page, allowed form box to expand, and added password confirmation box and feedback on account security"}, {"post_id": 80866, "ts": "2026-10-19T03:11:43Z", "hours": 1.0806, "text": "ATTENTION, SHIPWRIGHTS!! HERE, PLEASE!! HERE!! READ BELOW!!! i couldn’t edit the ship message’s contents, but hopefully you see this message! here are some things about the (new) ship… ▸ the new link for my project is here: https://dofresh.vercel.app . please use the credentials stardance_tester for both the username and the password!! THIS HAS ALL THE DATA FOR THE ACCOUNT, OR ELSE YOU NEED TO CREATE YOUR OWN DATA FOR YOUR ACCOUNT! ▸AI was NOT used for my devlogs, AI declaration, ship message, or README. i copied ASCII art, GitHub commit messages, and stylized font to the devlogs, not AI-generated summaries. i wrote my AI declaration in a separate Google Docs because my computer tended to restart and update at the wrong times. i wrote my ship message by myself! i used a part of my app description for the README, which, again, I wrote by myself. i have screenshots of my work below. anyways, for the devlog.. fixed the chat page so that a message can’t be sent while another is still generating!! debugged record() not establishing the variable recent_completed_pair before using it in the else-if conditional"}, {"post_id": 80287, "ts": "2026-10-17T03:50:49Z", "hours": 0.8883, "text": "debugged the refreshing lists not appearing at the sidebar debugged the ‘i did list’ not working debugged subtasks not appearing changed hosting platform from Render to Vercel! https://dofresh.vercel.app/ new link: https://dofresh.vercel.app/"}, {"post_id": 79439, "ts": "2026-10-14T00:10:48Z", "hours": 1.7119, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #39 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ hopefully the last devlog!! today, my very artistically talented friend gave me some very nice feedback about the login page, both directly and indirectly. sooo… debugged the list titles appearing as ‘undefined’ modified the login and sign-up pages!! aren’t they just so pretty [totally not similar]"}, {"post_id": 79078, "ts": "2026-10-12T16:12:33Z", "hours": 2.3017, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #38 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ with the Free tier for Hugging Face being closed, I switched to using Groq for API calls!! refined the chat feature by adding previous message context and restructuring the user task data for the migration to django fixed sidebar sign out button toggle and Chat textbox size changing debugged track page not appearing edited looks of completion tracking graph added task list appearing with breaks for task page tooltips"}, {"post_id": 78888, "ts": "2026-10-11T21:41:51Z", "hours": 0.8911, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #37 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ added formatting and HTML tag support for article page debugged 0/0 tasks and 0/0 list completion modal, which spiraled to infinity added NASA pictures for article iamges"}, {"post_id": 78499, "ts": "2026-10-11T00:12:26Z", "hours": 0.9383, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #36 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ fixed 500 Service Error for record() in views.py, optimizing iteration through list data and refining logic!!"}, {"post_id": 78238, "ts": "2026-10-10T02:44:32Z", "hours": 2.3283, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #35 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ now i really want to start shipping…! and submitting… please… today, sitting in the subway & waiting for/on my train, i refactored the advice page with a new Article class to dynamically display articles and created a new article detail page! updated advice.html to loop through articles, all objects of class Article in models.py, and display them dynamically added article.html template and the URL article/<int:article_id> added new CSS styles for article layout and text formatting (especially pre HTML blocks) i tried to upload images for the article cards into the database, but in production, i would need to find a cloud service provider (…and i need more )… so i reversed my hard work and uploaded the images to the static folder instead. additionally: moved the welcome modal and the refreshing notification/progress report modal HTML from index.html to layout.html so that the users would be able to see them in other pages of the website & debugged this debugged / cleaned up the logic and code for the tracking page’s fill-when-blank graphics."}, {"post_id": 77984, "ts": "2026-10-09T03:42:34Z", "hours": 4.4894, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #34 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ created + debugged completeRefreshingTask() from nonfunctional buggy to visibly seamless condition. debugged the function call’s missing button parameter at the click event handler. simplified idsToChange array composition, debugged parent to-do box HTML getting, added view.py function for backend reflection and change. added and debugged support for completing and matching subtasks & parent tasks.added animations and implemented/fixed logic structure of function. implemented, improved, and debugged task completion function components and edge case logic. tracked down and debugged one case of subtask handling error in addHTMLCompletedRefreshingTask() by changing the original JS key ‘subTasks’ to ‘subtasks’ and ‘parentTask’ to ‘parent_task’. added CSRF tokens to layout.html to enable POST methods for the general record/ and setLastDate() functions. debugged track.js to solve naming conflict in repeated uploads. added confetti and fireworks effect to task completion animations. moved Lumi from top of screen to stay in the sidebar for the user’s continuous view. debugged parent tasks switching the activeness of subtasks. added a ‘Refreshing tasks completed:’ counter at the top of the I Did List added today’s tasks to update the Refreshing Tasks Completed count. enabled the count text to collapse with the sidebar list. fixed some remaining localStorage-reliant code and the welcome modal’s sequencing. fixed Lumi position in login page. Debugged last_accessed_date being set in an empty user state."}, {"post_id": 75779, "ts": "2026-10-01T02:54:37Z", "hours": 2.6497, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #33 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ implemented set_last_date API endpoint and update last accessed date logic in views. refactored date handling in layout.js and script.js and designed date structure (ISO string format) to free conflict in regional time changes. migrated task completion recording function to Django (work-in-progress, not tested thoroughly). debugged and refactored the completion of tasks and updating completed tasks for improved performance and smooth HTML animation sequences & transitions. [added a new boolean condition to updateCompletedDiv so that it wouldn’t need to re-add the tasks every time it ran. yay performance improvement!]"}, {"post_id": 75397, "ts": "2026-09-29T23:02:30Z", "hours": 1.1839, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #32 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ debugged I Did List integration with Django; working as usual now. re-implemented Chat functions [display, Django Message models, and API calls]. started layout.js’s lastAccessedDate and refreshing date record functions with Django migration."}, {"post_id": 75054, "ts": "2026-09-29T00:39:37Z", "hours": 3.4697, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #31 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ added edit task, edit details, and remove task functionalities. implemented Django migration for track page!! added mock test data and confirmed that the track page works edited subtasks attribute to lists and edited views.py for Task objects to debug duplicate ID tasks. the django migration is going smoothly!! i’m quite proud of myself for getting editTask() and editDetails() in less than 5 minutes each. done in one go!!"}, {"post_id": 73437, "ts": "2026-09-25T02:47:56Z", "hours": 1.0464, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #30 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged addTodoBox() implementation with fetch()… turns out response.json() was missing the ()!! implemented removeTodoBox() and addTask() with matching Python views and functions getting there… kind of getting there… i need to finish this off…"}, {"post_id": 72916, "ts": "2026-09-24T00:56:49Z", "hours": 1.4336, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #29 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged to-do list and task HTML appearance with JavaScript fetch and new Django interactions established new data/fetch/global constant variables throughout script.js debugged I Did list’s usage of localStorage enabled adding lists and renaming lists with Django functions!"}, {"post_id": 72466, "ts": "2026-09-23T01:00:10Z", "hours": 5.9472, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #28 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ on the way to a full switch to Django: added login, logout, and signup views and functionalities to allow different users & management through the admin page working through bridging original usage of ‘localStorage’ and Django’s SQLite database—replacing many JavaScript functions with fetch and API calls drafted task, to-do list, and chat messages’ models in models.py fairly completed the HTML appearance for the JS -> Python fetch switch. app correctly generates the to-do lists, tasks, completed tasks, completed refreshing tasks, buttons, and subtasks"}, {"post_id": 68937, "ts": "2026-09-16T02:24:10Z", "hours": 3.2589, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #27 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored ‘onclick’ event listeners to conditionals and casework using event.target.nearest(). removed setListeners() entirely, saving memory leaks and unneeded recursive usage of setListeners(). uploaded the app on Render (for free!!)!! changing DoFresh platform from Flask to Django! initialized app + project foundations, changed settings, established urls, views, and models -> all task-related functions are working. still work-in-process for API calls and the backend."}, {"post_id": 67643, "ts": "2026-09-13T19:58:03Z", "hours": 2.2042, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #26 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added smooth collapsing/expanding animations for task addition and removal nested completed-for-good tasks in the completed tasks div and debugged the task ID retrieval in script.js debugged task completion handling and every small issue arising with each update and tweak"}, {"post_id": 64573, "ts": "2026-09-09T02:37:42Z", "hours": 5.3239, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #25 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added zero-state filler graphics to the track page! replaced querySelector with getElementById and getElementsByClassName for better performance, speed, and efficiency all around the app. added filler div for chat UI lots of minor tweaks to UX in the task add-remove-check sequence of the dashboard page"}, {"post_id": 61236, "ts": "2026-09-04T02:16:54Z", "hours": 4.9286, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #24 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged removal and creation of tasks with refactored js localstorage system! added zero state filler for main page if no boxes are present. debugged the different day headers showing up in the ‘I Did!’ list so that they don’t appear when no tasks are there at all. filler image work-in-progress. modified task creation to initialize with empty task strings instead of default text. cleaned up unused code and improved readability."}, {"post_id": 57019, "ts": "2026-08-29T02:54:53Z", "hours": 0.8256, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #23 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added headers and div s for the different completion dates in the I Did List implemented date formatting functions in script.js and organized/debugging the display and orientation of I Did list items so that both refreshing and standard, completed-today and completed-previously tasks would appear correctly."}, {"post_id": 56357, "ts": "2026-08-28T03:17:22Z", "hours": 8.3, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #22 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added streak activity chart, maximum streak, and longest active streak widgets to the track v.2 page! implemented ‘I Did List’ to keep track of completed tasks with date tags. keeps track of refreshing tasks’ completion over 1 week and all of the standard task completions on a collapsible sidebar in the dashboard. there are a lot of things to organize when dealing with dates… ISO date format, JS dateString format, parsing into milliseconds for comparison, etc. give me my strawberry coding notebook 🥲🥲 at least i’m having fun"}, {"post_id": 51180, "ts": "2026-08-20T18:00:30Z", "hours": 3.5881, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #21 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ day 2 of refactoring the whole track system… added activity heatmap chart after refactoring task completion chart implemented an activity heatmap to visualize task completion over time created a system of div s and span s for a “Github heatmap” orientation. added Bootstrap tooltips to display more information. much CSS effort was invested in accessibility + making a clean scrolling system and the weekday/month grid"}, {"post_id": 50666, "ts": "2026-08-19T22:56:32Z", "hours": 2.6619, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #20 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ created a blinking passive mode animation for Lumi refactored setLumiCostume function to loop the blinking animation without pause or transition effects (work in progress to make smoother!) decided to refactor track !! 600 lines of code… hopefully it’ll come alive again… added chartCompletion function to show number of completed tasks across days. JavaScript dynamics and Chart.js, CSS to create a responsive grid for the track dashboard, and HTML to reorder elements whoo"}, {"post_id": 49892, "ts": "2026-08-18T21:09:16Z", "hours": 1.6903, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #19 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ went through the whole process of editing the jumping animation again so that it would align better with the existing static character… yay… 🥹🥹 added lumi to the top of the to-do list and added animation for task completion"}, {"post_id": 49316, "ts": "2026-08-18T02:05:03Z", "hours": 0.4831, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #18 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added to-do list interaction to progress circle. debugged and refactored refresh notification modal display logic. designing time!! work in progress: a gamification (?) system and a star icon. say hi to lumi!! i did NOT spend 26 minutes on this… that’s just on the debugging… please show lumi some love and affectionate feedback!! i’ve never animated anything in my life before. ⭐ 💌"}, {"post_id": 48614, "ts": "2026-08-17T02:34:54Z", "hours": 2.84, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #17 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added new modal to pop up with ‘it’s a new day!’ and completion information. work in progress. added progress circle animations added a completedDate portion to standard to-do tasks so that daily reports can be yielded enabled tooltips for hovering over sidebar navigation updated styles for various components brainstorming several design ideas…"}, {"post_id": 47844, "ts": "2026-08-16T02:07:37Z", "hours": 2.4144, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #16 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged preservation and correction of chart generation settings (i.e. no weekly history with monthly chart type) adjusted color schemes and area fill for charts added dropdown task menus in track page for subtask organization and access enabled the “mainstream” task to be clicked without enabling dropdown, instead relying on hover to toggle dropdown menu note: the data is fake! i haven’t been doing the stardance challenge since may ;)"}, {"post_id": 47233, "ts": "2026-08-15T00:47:56Z", "hours": 1.96, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #15 – shoot for the stars like 📸 ˚₊‧ ଳ ‧₊˚ ⋅ debugged completion and re-activation of both subtasks and “mainstream” tasks! fixed subtask element selection in different task-controlling functions; improved localStorage handling for task completion and prevented duplicate entries. the long-awaited UI update!! used a free gradient as a background, edited opacity and blur in layout.css. changed color schemes further and added glassy / transparency aesthetic to to-do boxes. debugged the case where task dropdown menus didn’t disappear when other tasks were clicked!! small UX updates that make life significantly less frustrating. (small when they’re there, big when they’re not… guys… i’m a totally unartistic soul and a coder… ui/ux designers please save me!!! we love you 💖💖)"}, {"post_id": 46381, "ts": "2026-08-13T15:37:45Z", "hours": 1.2958, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #14 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged completion and re-activation of subtasks and “mainstream” tasks. fixed subtask element selection in functions; improved localStorage handling for task completion and prevented duplicate entries!"}, {"post_id": 45971, "ts": "2026-08-12T20:05:01Z", "hours": 1.8119, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #13 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ lucky number #13… i’m certainly suffering because of the subtask changes… 😄 added CSS and adjusted JavaScript to prevent disabling accordion collapse (conflict with new task dropdown) added CSS to task dropdown for hover-appear features and styling. refactored JavaScript: enabled proper removal and completion of tasks + subtasks! if a “mainstream” task is removed, so are all its substacks. a substack is removed cleanly. similarly, if an active “mainstream” task is completed, so are all of its subtasks. if it’s recovered from completion, however, the subtasks remain completed."}, {"post_id": 45430, "ts": "2026-08-11T21:19:26Z", "hours": 3.2161, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #12 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ updated CSS styles for buttons and task elements to improve layout and aesthetics: changed button styles from Bootstrap’s primary blue to custom logo purple added dropdown menus for tasks for another layer of safety in deletion added subtasks! (major change… help…) adjusted localStorage interactions, data structure, HTML/CSS code, and JavaScript logic for subtask management. improved user experience by adding focus and click event listeners for task editing and subtasks. had to decide whether to nestle subtasks within their parent tasks or by themselves in localStorage. finally settled on keeping all tasks on the same level for the sake of accessing them easily—instead, each subtask has a parentTask key, and a “mainstream” task has an array of their substack IDs."}, {"post_id": 44913, "ts": "2026-08-10T23:48:07Z", "hours": 1.9881, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #11 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ lots of small updates for this devlog. added loading spinner to chat function. updated and debugged styles—padding, sidebar, the body moving instead of overlapping with the expanded sidebar. updated chat message time logging. it’s the small things that matter… ;-;"}, {"post_id": 44371, "ts": "2026-08-10T02:46:29Z", "hours": 4.8058, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #10 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ heavily edited and debugged the new sidebar. adjusted previous javascript and html to accommodate it: updated padding and margin styles for better alignment. refactored layout structure to improve sidebar functionality and aesthetics. added JavaScript functionality for sidebar toggle and dynamic list generation in layout.js. removed unnecessary sidebar code and adjusted layout accordingly. implemented typewriter effect for generated chat responses! ⌨️"}, {"post_id": 42901, "ts": "2026-08-07T21:07:05Z", "hours": 2.0761, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #9 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored chat response handling and improved error handling/user display. debugged empty-space messages for home page. updated sidebar navigation link UI and enhanced layout structure."}, {"post_id": 41699, "ts": "2026-08-06T02:45:42Z", "hours": 4.6119, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #8 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added chat message storage and retrieval with a sql database! includes a refresh function w/ a safety modal improved chat UI [slightly, i really need to improve the entire app’s UI. designers help me. i’m aesthetic but i need to learn web UI ㅠ]"}, {"post_id": 40970, "ts": "2026-08-04T20:59:32Z", "hours": 3.9067, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #7– shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ attempting to connect huggingface’s ai models to dofresh as backend api have attempted for 3 hours and 52 minutes and success!! need to refine formatting, token length, and css styling, but the backend is connected and running."}, {"post_id": 39230, "ts": "2026-08-02T01:56:29Z", "hours": 0.8717, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #6 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added dynamic display of advice articles [wip] updated advice HTML structure and CSS for improved layout"}, {"post_id": 38596, "ts": "2026-08-01T02:25:26Z", "hours": 0.8856, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #5 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added HTML and CSS template for the advice page, which will feature a series of blogs offering advice on productivity, mental health, and consistent growth [based on personal experiences] considering using free AI APIs to create an interactive analysis/support chatbot… please recommend me some free sources if you know any!! ❤️"}, {"post_id": 37637, "ts": "2026-07-30T14:53:42Z", "hours": 1.9881, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #4 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ each task has a collapsible ‘details’ textarea! (i) modified HTML and CSS to accommodate changes (ii) modified JavaScript [mostly the .parentElement locations] to adjust to structure (iii) disabled space-key toggle so that the user’s typing wouldn’t be interrupted updated the track page’s sidebar from position: fixed; to position: relative; and juggled around CSS + CSS to restore the page structure debugged: the fill-if-blank text now appears only once, even when a completed task is deleted and the number of active tasks is consistently 0"}, {"post_id": 37090, "ts": "2026-07-29T15:56:15Z", "hours": 1.4378, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #3 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored localStorage format of storing tasks → {taskId: ‘task_1785339829783’, task: ‘look out the window’, details: ‘look out at the sky’, completedDates: []}. - this took a lot of effort, as does all structural change to storage in javascript. every function that pulled task data from localStorage had to be edited to accommodate this change, although i brought it upon myself by starting in the wrong direction. added ‘details’ to each task and styled them as textareas! updated alert for empty charts; prepended now, rather than appearing below the empty canvas"}, {"post_id": 36668, "ts": "2026-07-28T21:30:55Z", "hours": 1.275, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #2 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added randomized text for filling blank pages :D changed the stored date formats from date string s to ISO string for cleaner splitting and organization debugged removing the completed tasks! [i felt like a forensic scientist, only with console.log(‘this should be appearing more than once’) and lots of if-else statements]. turns out i was forgetting to setListeners() for the newly created HTML task elements. added charts tracking monthly progress [work in progress]"}, {"post_id": 36359, "ts": "2026-07-28T12:42:27Z", "hours": 0.4286, "text": "𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #1 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added safety modal boxes for removing to-do lists. debugged removal of completed tasks. to-do: ⋅˚₊‧ debug the completed tasks more! right now, only one completed task can be deleted at a time. uh-oh… ⋅˚₊‧"}]...
|
Title: DoFresh by @promise | Stardance
Devlogs:
𝐍 Title: DoFresh by @promise | Stardance
Devlogs:
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #1 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added safety modal boxes for removing to-do lists. debugged removal of completed tasks. to-do: ⋅˚₊‧ debug the completed tasks more! right now, only one completed task can be deleted at a time. uh-oh… ⋅˚₊‧
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #2 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added randomized text for filling blank pages :D changed the stored date formats from date string s to ISO string for cleaner splitting and organization debugged removing the completed tasks! [i felt like a forensic scientist, only with console.log(‘this should be appearing more than once’) and lots of if-else statements]. turns out i was forgetting to setListeners() for the newly created HTML task elements. added charts tracking monthly progress [work in progress]
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #3 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored localStorage format of storing tasks → {taskId: ‘task_1785339829783’, task: ‘look out the window’, details: ‘look out at the sky’, completedDates: []}. - this took a lot of effort, as does all structural change to storage in javascript. every function that pulled task data from localStorage had to be edited to accommodate this change, although i brought it upon myself by starting in the wrong direction. added ‘details’ to each task and styled them as textareas! updated alert for empty charts; prepended now, rather than appearing below the empty canvas
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #4 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ each task has a collapsible ‘details’ textarea! (i) modified HTML and CSS to accommodate changes (ii) modified JavaScript [mostly the .parentElement locations] to adjust to structure (iii) disabled space-key toggle so that the user’s typing wouldn’t be interrupted updated the track page’s sidebar from position: fixed; to position: relative; and juggled around CSS + CSS to restore the page structure debugged: the fill-if-blank text now appears only once, even when a completed task is deleted and the number of active tasks is consistently 0
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #5 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added HTML and CSS template for the advice page, which will feature a series of blogs offering advice on productivity, mental health, and consistent growth [based on personal experiences] considering using free AI APIs to create an interactive analysis/support chatbot… please recommend me some free sources if you know any!! ❤️
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #6 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added dynamic display of advice articles [wip] updated advice HTML structure and CSS for improved layout
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #7– shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ attempting to connect huggingface’s ai models to dofresh as backend api have attempted for 3 hours and 52 minutes and success!! need to refine formatting, token length, and css styling, but the backend is connected and running.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #8 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added chat message storage and retrieval with a sql database! includes a refresh function w/ a safety modal improved chat UI [slightly, i really need to improve the entire app’s UI. designers help me. i’m aesthetic but i need to learn web UI ㅠ]
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #9 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored chat response handling and improved error handling/user display. debugged empty-space messages for home page. updated sidebar navigation link UI and enhanced layout structure.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #10 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ heavily edited and debugged the new sidebar. adjusted previous javascript and html to accommodate it: updated padding and margin styles for better alignment. refactored layout structure to improve sidebar functionality and aesthetics. added JavaScript functionality for sidebar toggle and dynamic list generation in layout.js. removed unnecessary sidebar code and adjusted layout accordingly. implemented typewriter effect for generated chat responses! ⌨️
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #11 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ lots of small updates for this devlog. added loading spinner to chat function. updated and debugged styles—padding, sidebar, the body moving instead of overlapping with the expanded sidebar. updated chat message time logging. it’s the small things that matter… ;-;
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #12 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ updated CSS styles for buttons and task elements to improve layout and aesthetics: changed button styles from Bootstrap’s primary blue to custom logo purple added dropdown menus for tasks for another layer of safety in deletion added subtasks! (major change… help…) adjusted localStorage interactions, data structure, HTML/CSS code, and JavaScript logic for subtask management. improved user experience by adding focus and click event listeners for task editing and subtasks. had to decide whether to nestle subtasks within their parent tasks or by themselves in localStorage. finally settled on keeping all tasks on the same level for the sake of accessing them easily—instead, each subtask has a parentTask key, and a “mainstream” task has an array of their substack IDs.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #13 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ lucky number #13… i’m certainly suffering because of the subtask changes… 😄 added CSS and adjusted JavaScript to prevent disabling accordion collapse (conflict with new task dropdown) added CSS to task dropdown for hover-appear features and styling. refactored JavaScript: enabled proper removal and completion of tasks + subtasks! if a “mainstream” task is removed, so are all its substacks. a substack is removed cleanly. similarly, if an active “mainstream” task is completed, so are all of its subtasks. if it’s recovered from completion, however, the subtasks remain completed.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #14 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged completion and re-activation of subtasks and “mainstream” tasks. fixed subtask element selection in functions; improved localStorage handling for task completion and prevented duplicate entries!
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #15 – shoot for the stars like 📸 ˚₊‧ ଳ ‧₊˚ ⋅ debugged completion and re-activation of both subtasks and “mainstream” tasks! fixed subtask element selection in different task-controlling functions; improved localStorage handling for task completion and prevented duplicate entries. the long-awaited UI update!! used a free gradient as a background, edited opacity and blur in layout.css. changed color schemes further and added glassy / transparency aesthetic to to-do boxes. debugged the case where task dropdown menus didn’t disappear when other tasks were clicked!! small UX updates that make life significantly less frustrating. (small when they’re there, big when they’re not… guys… i’m a totally unartistic soul and a coder… ui/ux designers please save me!!! we love you 💖💖)
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #16 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged preservation and correction of chart generation settings (i.e. no weekly history with monthly chart type) adjusted color schemes and area fill for charts added dropdown task menus in track page for subtask organization and access enabled the “mainstream” task to be clicked without enabling dropdown, instead relying on hover to toggle dropdown menu note: the data is fake! i haven’t been doing the stardance challenge since may ;)
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #17 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added new modal to pop up with ‘it’s a new day!’ and completion information. work in progress. added progress circle animations added a completedDate portion to standard to-do tasks so that daily reports can be yielded enabled tooltips for hovering over sidebar navigation updated styles for various components brainstorming several design ideas…
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #18 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added to-do list interaction to progress circle. debugged and refactored refresh notification modal display logic. designing time!! work in progress: a gamification (?) system and a star icon. say hi to lumi!! i did NOT spend 26 minutes on this… that’s just on the debugging… please show lumi some love and affectionate feedback!! i’ve never animated anything in my life before. ⭐ 💌
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #19 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ went through the whole process of editing the jumping animation again so that it would align better with the existing static character… yay… 🥹🥹 added lumi to the top of the to-do list and added animation for task completion
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #20 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ created a blinking passive mode animation for Lumi refactored setLumiCostume function to loop the blinking animation without pause or transition effects (work in progress to make smoother!) decided to refactor track !! 600 lines of code… hopefully it’ll come alive again… added chartCompletion function to show number of completed tasks across days. JavaScript dynamics and Chart.js, CSS to create a responsive grid for the track dashboard, and HTML to reorder elements whoo
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #21 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ day 2 of refactoring the whole track system… added activity heatmap chart after refactoring task completion chart implemented an activity heatmap to visualize task completion over time created a system of div s and span s for a “Github heatmap” orientation. added Bootstrap tooltips to display more information. much CSS effort was invested in accessibility + making a clean scrolling system and the weekday/month grid
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #22 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added streak activity chart, maximum streak, and longest active streak widgets to the track v.2 page! implemented ‘I Did List’ to keep track of completed tasks with date tags. keeps track of refreshing tasks’ completion over 1 week and all of the standard task completions on a collapsible sidebar in the dashboard. there are a lot of things to organize when dealing with dates… ISO date format, JS dateString format, parsing into milliseconds for comparison, etc. give me my strawberry coding notebook 🥲🥲 at least i’m having fun
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #23 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added headers and div s for the different completion dates in the I Did List implemented date formatting functions in script.js and organized/debugging the display and orientation of I Did list items so that both refreshing and standard, completed-today and completed-previously tasks would appear correctly.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #24 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged removal and creation of tasks with refactored js localstorage system! added zero state filler for main page if no boxes are present. debugged the different day headers showing up in the ‘I Did!’ list so that they don’t appear when no tasks are there at all. filler image work-in-progress. modified task creation to initialize with empty task strings instead of default text. cleaned up unused code and improved readability.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #25 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added zero-state filler graphics to the track page! replaced querySelector with getElementById and getElementsByClassName for better performance, speed, and efficiency all around the app. added filler div for chat UI lots of minor tweaks to UX in the task add-remove-check sequence of the dashboard page
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #26 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ added smooth collapsing/expanding animations for task addition and removal nested completed-for-good tasks in the completed tasks div and debugged the task ID retrieval in script.js debugged task completion handling and every small issue arising with each update and tweak
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #27 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ refactored ‘onclick’ event listeners to conditionals and casework using event.target.nearest(). removed setListeners() entirely, saving memory leaks and unneeded recursive usage of setListeners(). uploaded the app on Render (for free!!)!! changing DoFresh platform from Flask to Django! initialized app + project foundations, changed settings, established urls, views, and models -> all task-related functions are working. still work-in-process for API calls and the backend.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #28 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ on the way to a full switch to Django: added login, logout, and signup views and functionalities to allow different users & management through the admin page working through bridging original usage of ‘localStorage’ and Django’s SQLite database—replacing many JavaScript functions with fetch and API calls drafted task, to-do list, and chat messages’ models in models.py fairly completed the HTML appearance for the JS -> Python fetch switch. app correctly generates the to-do lists, tasks, completed tasks, completed refreshing tasks, buttons, and subtasks
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #29 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged to-do list and task HTML appearance with JavaScript fetch and new Django interactions established new data/fetch/global constant variables throughout script.js debugged I Did list’s usage of localStorage enabled adding lists and renaming lists with Django functions!
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #30 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ ⋅ debugged addTodoBox() implementation with fetch()… turns out response.json() was missing the ()!! implemented removeTodoBox() and addTask() with matching Python views and functions getting there… kind of getting there… i need to finish this off…
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #31 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ added edit task, edit details, and remove task functionalities. implemented Django migration for track page!! added mock test data and confirmed that the track page works edited subtasks attribute to lists and edited views.py for Task objects to debug duplicate ID tasks. the django migration is going smoothly!! i’m quite proud of myself for getting editTask() and editDetails() in less than 5 minutes each. done in one go!!
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #32 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ debugged I Did List integration with Django; working as usual now. re-implemented Chat functions [display, Django Message models, and API calls]. started layout.js’s lastAccessedDate and refreshing date record functions with Django migration.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #33 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ implemented set_last_date API endpoint and update last accessed date logic in views. refactored date handling in layout.js and script.js and designed date structure (ISO string format) to free conflict in regional time changes. migrated task completion recording function to Django (work-in-progress, not tested thoroughly). debugged and refactored the completion of tasks and updating completed tasks for improved performance and smooth HTML animation sequences & transitions. [added a new boolean condition to updateCompletedDiv so that it wouldn’t need to re-add the tasks every time it ran. yay performance improvement!]
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #34 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ created + debugged completeRefreshingTask() from nonfunctional buggy to visibly seamless condition. debugged the function call’s missing button parameter at the click event handler. simplified idsToChange array composition, debugged parent to-do box HTML getting, added view.py function for backend reflection and change. added and debugged support for completing and matching subtasks & parent tasks.added animations and implemented/fixed logic structure of function. implemented, improved, and debugged task completion function components and edge case logic. tracked down and debugged one case of subtask handling error in addHTMLCompletedRefreshingTask() by changing the original JS key ‘subTasks’ to ‘subtasks’ and ‘parentTask’ to ‘parent_task’. added CSRF tokens to layout.html to enable POST methods for the general record/ and setLastDate() functions. debugged track.js to solve naming conflict in repeated uploads. added confetti and fireworks effect to task completion animations. moved Lumi from top of screen to stay in the sidebar for the user’s continuous view. debugged parent tasks switching the activeness of subtasks. added a ‘Refreshing tasks completed:’ counter at the top of the I Did List added today’s tasks to update the Refreshing Tasks Completed count. enabled the count text to collapse with the sidebar list. fixed some remaining localStorage-reliant code and the welcome modal’s sequencing. fixed Lumi position in login page. Debugged last_accessed_date being set in an empty user state.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #35 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ now i really want to start shipping…! and submitting… please… today, sitting in the subway & waiting for/on my train, i refactored the advice page with a new Article class to dynamically display articles and created a new article detail page! updated advice.html to loop through articles, all objects of class Article in models.py, and display them dynamically added article.html template and the URL article/<int:article_id> added new CSS styles for article layout and text formatting (especially pre HTML blocks) i tried to upload images for the article cards into the database, but in production, i would need to find a cloud service provider (…and i need more )… so i reversed my hard work and uploaded the images to the static folder instead. additionally: moved the welcome modal and the refreshing notification/progress report modal HTML from index.html to layout.html so that the users would be able to see them in other pages of the website & debugged this debugged / cleaned up the logic and code for the tracking page’s fill-when-blank graphics.
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #36 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ fixed 500 Service Error for record() in views.py, optimizing iteration through list data and refining logic!!
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #37 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ added formatting and HTML tag support for article page debugged 0/0 tasks and 0/0 list completion modal, which spiraled to infinity added NASA pictures for article iamges
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #38 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ with the Free tier for Hugging Face being closed, I switched to using Groq for API calls!! refined the chat feature by adding previous message context and restructuring the user task data for the migration to django fixed sidebar sign out button toggle and Chat textbox size changing debugged track page not appearing edited looks of completion tracking graph added task list appearing with breaks for task page tooltips
𝐍𝐨𝐰 𝐥𝐨𝐚𝐝𝐢𝐧𝐠. . . devlog #39 – shoot for the stars like 📸 ⋅˚₊‧ ଳ ‧₊˚ hopefully the last devlog!! today, my very artistically talented friend gave me some very nice feedback about the login page, both directly and indirectly. sooo… debugged the list titles appearing as ‘undefined’ modified the login and sign-up pages!! aren’t they just so pretty [totally not similar]
debugged the refreshing lists not appearing at the sidebar debugged the ‘i did list’ not working debugged subtasks not appearing changed hosting platform from Render to Vercel! https://dofresh.vercel.app/ new link: https://dofresh.vercel.app/
ATTENTION, SHIPWRIGHTS!! HERE, PLEASE!! HERE!! READ BELOW!!! i couldn’t edit the ship message’s contents, but hopefully you see this message! here are some things about the (new) ship… ▸ the new link for my project is here: https://dofresh.vercel.app . please use the credentials stardance_tester for both the username and the password!! THIS HAS ALL THE DATA FOR THE ACCOUNT, OR ELSE YOU NEED TO CREATE YOUR OWN DATA FOR YOUR ACCOUNT! ▸AI was NOT used for my devlogs, AI declaration, ship message, or README. i copied ASCII art, GitHub commit messages, and stylized font to the devlogs, not AI-generated summaries. i wrote my AI declaration in a separate Google Docs because my computer tended to restart and update at the wrong times. i wrote my ship message by myself! i used a part of my app description for the README, which, again, I wrote by myself. i have screenshots of my work below. anyways, for the devlog.. fixed the chat page so that a message can’t be sent while another is still generating!! debugged record() not establishing the variable recent_completed_pair before using it in the else-if conditional
added a custom user creation form to enable flexibility and clean error messages when signing up; debugged the sign-up page, allowed form box to expand, and added password confirmation box and feedback on account security
Ships:
What did you make? This is DoFresh, a refreshing task manager that turns consistency into records and graphs! What was challenging? On top of the various bugs that arose on the way to refine and polish various features, one challenge in creating DoFresh was designing and implementing the Track system. Firstly, the logic system surrounding behind user completion and daily refreshing was complex, especially when considering the users didn’t visit the website every day. Secondly, I strove to make graphs and tracking widgets that were self-explanatory and simple but stylish and understandable, and I had to refactor the Track page completely after I changed my data storage system, changing the types of charts and how each was organized. What are you proud of? I’m quite proud of how the website looks, as I’m really artistically untalented and never really got around to learning CSS or aesthetics or color theory. The purple prettiness of DoFresh is really an achievement for me, and I’m especially proud of how much design and UI/UX consideration I learned through this app. Now, when I open websites, I look at how they design their login pages, where they put their collapsible sidebar icons, and what headings they use—sideways, click-collapse, fixed above, sticky—and why. Another thing I’m quite proud of is the AI agent I personalized and implemented in the Chat page. I wired the API call system for Flask, then Django, with many small bugs for both scenarios, connecting the Python backend with HuggingFace’s free models. Then, two days after I began wrapping up and testing the site, HuggingFace removed its free tier altogether. (●__●) Thus I switched to using GroqCloud as a platform, making a new API key, and set to further refining how the bot understood the user’s completion data, programming it to fit DoFresh’s philosophy and purposes. What should people know so they can test your project? You can go into https://dofresh.onrender.com/ and log in with the credentials stardance_tester + stardance_tester (username + pw both) if you want an example with pre-filled data and records! Please note that (free tier) Render takes about ~40 seconds to load and may spin down to inactiveness if you leave it open and untouched....
|
1793008360.6742656
|
1793094760.6742656
|
|
35761
|
Ping Monitors by @vadex6 | Stardance
|
vadex6
|
0
|
101.41
|
0
|
[]
|
[{"post_id": 40319, "ts": "202 [{"post_id": 40319, "ts": "2026-08-03T19:17:18Z", "hours": 1.3769, "text": "Added real-time monitoring by making use of websockets listeners on the frontend to process live status updates (up/down), response latency, and incident states without refreshing the page."}, {"post_id": 29133, "ts": "2026-07-15T20:06:36Z", "hours": 100.0342, "text": "An uptime monitor that helps pings websites and send emails to the users when their websites are down"}]...
|
Title: Ping Monitors by @vadex6 | Stardance
Devlo Title: Ping Monitors by @vadex6 | Stardance
Devlogs:
An uptime monitor that helps pings websites and send emails to the users when their websites are down
Added real-time monitoring by making use of websockets listeners on the frontend to process live status updates (up/down), response latency, and incident states without refreshing the page....
|
1792676901.9640396
|
1793281701.9640396
|
|
16571
|
mocha by @Glitchy | Stardance
|
Glitchy
|
1
|
101.0
|
1806
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-13T18:57:02Z", "hours": 101.0, "multiplier": 17.94, "payout": 1806, "blessing": "neutral", "text": "I made a package manager for Windows, which is somewhat backwards compatible with scoop packages. To be honest there’s still a lot of work that I want to do, but I have exams and college application coming up soon so I can’t. That’s not to say I’m not happy with the state of the ship. At the very least it has all the core features that a package manager should have, but there are still a lot of bugs which is why this is only v0.0.1. The biggest challenge by far was trying to figure out how Scoop does things internally. A lot of stuff just doesn’t have documentation, so you have to dig through the really messy PowerShell source code.", "repo": "https://github.com/Protract-123/mocha", "demo": "https://github.com/Protract-123/mocha/releases/latest"}]...
|
[{"post_id": 67579, "ts": "202 [{"post_id": 67579, "ts": "2026-09-13T18:33:17Z", "hours": 1.7761, "text": "So I wrote a README, added a license (MIT of course) and setup CI/CD so that releases are automatically built and deployed. Honestly I forgot how hard it is to write a good README. You need to get a lot of information through without it looking like a wall of text."}, {"post_id": 67267, "ts": "2026-09-13T10:36:48Z", "hours": 5.8047, "text": "I forgot to make a devlog in between so this will be like 2 bigger devlogs. I parallelized bucket updates, which speeds it up quite a bit. This also allowed me to try out parallelism even more, which I plan to apply throughout the CLI later on. I also added configuration options for the runners which mocha shim will use to run certain file types. For example, you can set the python-runner to select the python version that’ll be used to run python scripts that are shimmed. Downloads now have a progress bar, so you don’t need to wonder whether something is happening or not during a long download. Finally env_set is fully supported since I added the relevant variable parsing. This was pretty much just me cleaning out the TODO list before I ship. I also did a lot of smaller bug fixes and refactors as seen below. fix(commands): prevent app installation if already installed (cb27d07) fix(commands): fix config opening with “start” (74f3679) fix(commands): correctly handle non-apps when upgrading (f7419f6) fix: make LogOutput go to Stdout not Stderr (bc10357) fix: handle empty versions correctly (2287da9) fix(pkg): remove correct temp dir (33189b6) fix(shim): warn for unknown shim extension (622c2b4) fix: skip downloads with no hash by default (69d4e35) fix: use correct timeout for downloads (44e527b) fix: drop unnecessary return value from GetExecutableEntries (9fd845c) fix(config): remove unused option (1339971) fix(commands): don’t error for valid results (87c4d6c) refactor(config): rename variables/functions (f253d9d) fix: use unique temp directories (a159e23) refactor: use fmt.Fprintln directly (d2d54bf)"}, {"post_id": 65401, "ts": "2026-09-10T14:55:22Z", "hours": 2.5386, "text": "Lots of small bug fixes and changes, I’ll just list them out: feat(cmd): allow removal of multiple shims in one execution (f2fae3f) fix(manifest): correctly ignore invalid shortcut entries (6a08478) fix(fileops): use correct registry type (5d5d796) fix(config): seed config with defaults (9dfaaff) fix(cmd): use correct release sources (a2a9ba1) fix(cmd): use bucket from install info (5a9109b) I also added support for more file types being shimmed, which helps a lot with compatibility. The file types are .py , .bat , .cmd , .jar and .ps1 ."}, {"post_id": 52474, "ts": "2026-08-22T16:37:15Z", "hours": 4.6758, "text": "Lot of time going into this devlog, but it makes sense since I did do a lot. I did this sweeping refactor of the entire commands module which moved around a lot of code. Essentially each command now gets it’s own directory under the commands module that represents it’s children/parents. For example commands/shim/remove/cmd.go contains code for the mocha shim remove command. Each cmd.go contains a Command struct that has the relevant fields and functions attached to it. This structure just makes things more organized and also means adding test files will be a bit easier since functionality is now isolated. I also sorted out the shim binary. So essentially https://github.com/ScoopInstaller/Shim offers different version of the shim binary which can be installed. Previously I hard coded the code to install cpp v0.1.0 but now users can run mocha shim binary releases to see the options and mocha shim binary setup to install their chosen binary. This also means we actually get the latest releases from GitHub."}, {"post_id": 51141, "ts": "2026-08-20T17:11:51Z", "hours": 3.6722, "text": "Finally got a bit of time to do a bit of development. First thing I did was remove a field from install.json to match scoop . This means that mocha should be a drop in replacement for existing scoop installs. Then I added partial support for env_set and env_add_path . The main thing I need to do to complete the feature is parse variables and replace them with the appropriate paths. These 2 fields are some of the last manifest fields I need to support besides pre/post (un)install hooks."}, {"post_id": 34596, "ts": "2026-07-25T13:39:02Z", "hours": 2.5778, "text": "My summer break has ended so development is going to be a lot slower from now. I added mocha outdated so you can list outdated apps before upgrading them to a newer version. Besides that I tweaked a lot of stuff related to CLI output. For example I changed search to output one table, and simply outputting exact matches at the top of that table. I also changed a lot of messages which were using LogOutput to LogInfo so they use the correct color and output to stderr and not stdout ."}, {"post_id": 31801, "ts": "2026-07-20T14:04:04Z", "hours": 1.5481, "text": "Not sure why I didn’t do this earlier, but I’ve added success messages to commands where it makes sense. Also added a success color to the config so you can change what the success color is. I do still need to improve CLI output quite a bit, but it’s slowly getting there."}, {"post_id": 30693, "ts": "2026-07-18T14:02:54Z", "hours": 2.1922, "text": "I’m writing this one right before F1 Qualifying at Spa! Continuing with the trend of some of my recent work, I improved what table outputs look like to be a little bit more readable. We now use proper separators in the form of Unicode Box Drawing Characters . I also made column alignment configurable, which improves legibility for some commands like mocha bucket list and mocha cache show . I’ve attached an image of the scoop and mocha versions of bucket list so you can compare for yourself."}, {"post_id": 30286, "ts": "2026-07-17T18:51:34Z", "hours": 3.4797, "text": "I love refactoring!!!! I’ll probably end up spending another 20 hours just on refactoring because it’s so fun!!!! This time around I wanted to refactor the code so that our commands orchestrate stuff instead of the helper functions. For example, pkg.Install would first download a package, then install it, and then link it through shims and shortcuts all by itself. This causes issues because it means error messages become slightly worse, and it creates a class of bugs due to edge cases where we don’t necessarily want this order of orchestration. Hence I did a lot of refactoring in the pkg module. I also ended up adding a way to skip verification of downloads when downloading, installing or updating a package through --skip-verify . It’s a useful option in situations where there is a malformed manifest or simply no hash to begin with."}, {"post_id": 30054, "ts": "2026-07-17T10:28:53Z", "hours": 4.6269, "text": "mocha now supports a user defined theme for output colors. In the process I ended up doing a lot of stuff related to the config. First thing I did was swap to fatih/color for colored output, since it handles stuff like colors in command prompt and removing color when output is piped. Then I refactored the config module. Earlier I would pass around a MochaConfiguration object through every function. Now I use a config singleton that’s accessible from any function. Why? Because it means I don’t need to pass the object every time I want to log information. Also means I don’t need to pass mochaDir through almost every function in the codebase. Getting user defined themes was a bit complicated because I needed a good way to handle a default theme so output doesn’t look bad if parsing fails. I handled this by only using the configured theme if every color resolves properly. Otherwise output falls back to the already loaded default theme. Due to this you still get colored output even if there are errors or warning before the configuration and theme is loaded."}, {"post_id": 29066, "ts": "2026-07-15T18:30:47Z", "hours": 4.7214, "text": "So I’ve been doing a bit of refactoring, a bit of bug fixing and a bit of optimization. Essentially just polishing mocha before I work on the next feature. Here’s some of the stuff I did: created tests for ParseRefString to validate behavior cache manifest json between info calls since I/O is really slow bumped dependency versions refactored manifest/info.go Besides that I fixed the uninstall flow since it was really bugged after the latest changes. Essentially mocha would uninstall apps with incorrect info. It would also try to remove shims/shortcuts for apps which don’t have any active shims/shortcuts. I then added a bit of logging since the uninstall command didn’t give any user output for whatever reason (i forgot to earlier)."}, {"post_id": 27086, "ts": "2026-07-12T10:29:45Z", "hours": 6.4975, "text": "This is going to be the equivalent of 2 devlogs since I thought I made one earlier for persists but I didn’t. New feature! We now handle persist items in order to store data between versions. These are files which are persisted between versions of an app. Lets take git as an example to explain why persist exists. Say you want to make sure your git config isn’t deleted every time you update. The issue with this is that the config file is saved in the version specfic directory. To resolve this we can keep the config in $MOCHA_DIR/persist and then symlink the config to where it needs to be, which is essentially what persist tells us to do. Since we handled persist items last time we can now implement mocha upgrade to update apps. The way scoop handles updates is by first removing anything that references the app, like shortcuts or shims . Then we just follow the install process from scratch. This leaves the old version available in case a user wants to revert versions due to a bug, while also updating to the latest available version. This can be seen in the video below, which shows me updating llama.cpp-hip-radeon ."}, {"post_id": 23572, "ts": "2026-07-06T16:39:13Z", "hours": 3.53, "text": "We now create shortcuts! This means any GUI apps should show up properly in the start menu, just like they do when you install with scoop . All I really had to do was a bit of orchestration since I decided to vendor in an implementation from https://github.com/jxeng/shortcut Besides that I expanded the number of apps that are supported by implementing a bit of code that handle architecture specific bin fields, along with bin fields which store 2D arrays. I also cleared up some of the TODO items. I swapped the junction implementation to an implementation from https://github.com/nyaosorg/go-windows-junction since we were previously shelling out to CLI. That and I added a bit more zip bomb protection For the purposes of the video below I changed the location which shortcuts get put to my desktop. It’ll probably be configurable, and match scoop by putting shortcuts in the startup menu by default"}, {"post_id": 22839, "ts": "2026-07-05T13:36:18Z", "hours": 3.3089, "text": "As I mentioned in the previous devlog I added good help information to every bit of the CLI. It’s surprisingly difficult to write good help messages which explains everything to users in a few words I also changed the behaviour of the mocha cache clear command to not clear all cache by default. That’s now gated behind the --all flag in order to match scoop a bit more"}, {"post_id": 21420, "ts": "2026-07-03T11:02:24Z", "hours": 1.0722, "text": "Typically I don’t want to make devlogs for small stuff like this, but this is something I found really cool. So I was working on help messages for all the commands when I realized that mocha bucket list felt a bit slower than pretty much every other command. This is because we need to shell out to git 2 times per bucket, and I had 4 buckets added. While 8 git commands might not sound like a lot, it was enough to make mocha bucket list feel slow. So what I did is I parallelized the metadata fetching through an errgroup . Instead of fetching the metadata for each bucket in order, we fetch the metadata for all 4 buckets simultaneously. This led to a big performance uplift. About 3 times faster than the old version of mocha , and just over 12 times faster than scoop for this operation. See the video below."}, {"post_id": 21386, "ts": "2026-07-03T09:17:07Z", "hours": 2.2464, "text": "I finished up mocha uninstall and mocha list , which means you can actually manage installed apps instead of manually deleting them. There’s not much that goes into mocha uninstall . You just need to remove the relevant shims and app directories since the apps that mocha supports are all portable. mocha list is similarly simple. It’s just loops over the directories in $MOCHA_DIR/apps and looks for apps along with the versions installed for each app."}, {"post_id": 19910, "ts": "2026-07-01T10:53:02Z", "hours": 5.4625, "text": "So I added support for more apps by implementing more extractors. This means in theory any apps which don’t need a pre-install or post-install should work. To be more specific, I handle a few more properties on manifests. Those being extract_dir and innosetup , which inform how an app needs to be installed. I also implement 7zip and innounp as extractors to support more file formats which applications are distributed in. Of course there’s still a lot of work before I consider this ready for public use. I need to create commands for some basic operations like uninstalling, updating and listing apps. I also need to handle shortcuts otherwise GUI apps can’t be accessed from the start menu. Besides that I need to improve the user experience. As you can see in the video below mocha just sort of dumps everything to the console even if it’s not relevant. Help menus are also critical to get working properly."}, {"post_id": 18238, "ts": "2026-06-29T09:51:16Z", "hours": 3.7839, "text": "Finished up the code cleanup in commands , fileops and manifests . I did catch a few edge cases and some incorrect behavior in the process, which is why I always spend so much time reviewing code. I did use AI to assist with code review because I think it’s an area where AI shines. AI is really good at finding small errors or inconsistencies in the codebase which I probably wouldn’t notice. For example, it identified that the ManifestReferences argument was not a required argument for the download command, which meant no help message was displayed on incorrect usage like the other commands. One big thing I will work on eventually is console output. Right now errors are well formatted but a lot of the time commands just run stuff without providing a lot of insight into what actions they are taking which isn’t great. Even the help menu is pretty useless right now (see the image below). Extra context: A manifest reference is a pointer to an app (e.g. main/ [email protected] )"}, {"post_id": 17027, "ts": "2026-06-27T17:10:53Z", "hours": 5.3025, "text": "Before working on more features and expanding the amount of apps mocha actually supports I wanted to go through the codebase and do a lot of cleanup since the codebase is quite messy. There are silly mistakes in some files and bad implementations in others. Hence the time I spent during this period was focused on moving code to where it should be and cleaning up some edge cases, specifically related to the bucket , config and shim modules. A good example of this is moving the code to get the active config to the config module instead of leaving it in main.go . Next up will be refactoring the commands , fileops , and manifest modules. I don’t have much to show so I figured I would present a feature I added but didn’t show earlier: the ability to skip cache hits with the --force flag when installing or downloading an app. Some context I forgot to add initially: I renamed the app module to manifest since I felt it was more accurate to what it actually handles scope wise."}, {"post_id": 15814, "ts": "2026-06-25T18:17:50Z", "hours": 2.5558, "text": "Huge milestone!!! I’ve gotten mocha install working for very basic apps! This means the entire process of downloading a file, then extracting it, then creating a junction and finally creating a shim now works for basic pieces of software! So in terms of what I actually did this devlog, I added cache hits to the download command since it’s relevant to the install command. I then implemented the aforementioned .zip extraction and junction creation. Then all that was left was a bit of orchestration, getting everything to work together properly. See a working install of innounp using mocha install below!"}, {"post_id": 15668, "ts": "2026-06-25T14:03:10Z", "hours": 0.7572, "text": "mocha update is another command which does very little but is very important. All it does is update the known_buckets file, and run git pull on all added buckets to update them. It can also update just the buckets you specify if you pass in an argument. I do need to improve the output of the command since it outputs raw git right now, but at least it’s functional. See the demo below."}, {"post_id": 14392, "ts": "2026-06-23T14:41:51Z", "hours": 6.9436, "text": "Spent a bit longer between devlogs this time, but it was worth it. So I realized the error messages were really bad. I was pretty much just passing errors up the call stack without adding any context, which isn’t great since it means our error messages will be useless to people reading them I therefore went through every single file of the codebase and wrote good error messages which add a bit of context every time we pass it up the call stack. I also did a bit of refactoring where I thought it would be worth it. For example in the shim module I now set the PE subsystem of the shim binary while it’s in memory instead of writing to disk twice. A few good examples of what the new error messages look like can be seen in the video below."}, {"post_id": 13054, "ts": "2026-06-21T10:47:05Z", "hours": 3.4069, "text": "Shims are simple in concept, complicated in reality. So essentially a shim in mocha is just an executable which calls another executable. It’s similar to a shortcut in that sense, except it shows up in $PATH Thankfully the scoop project already has a repository with 4 different implementations for the shim binary, so I can just have mocha shim download one of those binaries. The complicated part was the PE Subsystem. The PE subsystem is basically a bit of info in each binary which tells Windows whether it’s a console application, or a GUI application. We need to set the PE subsystem of the shim exe to the PE subsystem of the binary we are calling for Windows to execute the binary properly. Hence I need to read and write raw binary data. All of this is just the implementation for exe shims. Scoop itself contains implementations for .bat/.cmd , .ps1 , .jar , .py and linux binaries , all of which have wildly different implementations compared to .exe shims. The video below shows the working set of mocha shim commands (those being add , remove and list )."}, {"post_id": 12032, "ts": "2026-06-19T16:57:37Z", "hours": 1.8778, "text": "mocha cache is a simple command. It shows you what files are currently in $MOCHA_DIR/cache directory and it clears them out. One thing I noticed was that scoop cache show actually displays raw bytes instead of human readable file sizes for each cache entry, which is a bit odd since the total they display is human readable. Therefore I made my implementation mocha cache list display human readable sizes since that’s a more reasonable default."}, {"post_id": 11234, "ts": "2026-06-18T11:50:44Z", "hours": 2.2589, "text": "Fuzzy search is really really good. While implementing mocha search I noticed the results returned by scoop search were in alphabetical order, which doesn’t make a lot of sense. If I do scoop search git the first result should probably be git As a result my implementation of search uses github.com/sahilm/fuzzy which is a small library which provides a fuzzy search implementation. Scoop also checks for binary name matches, e.g. package biodiff can provide a binary called git-biodiff and show up in search results. I decided to remove this for now, since I personally find it a bit unnecessary. scoop search also lists all search results, which is okay when results are sorted alphabetically but doesn’t make sense when searches are relevance based. Therefore, by default mocha search will list exact matches plus the 20 most relevant search results. This can be overridden by the --count argument, where setting it to 0 displays all results. A demonstration of mocha search vs scoop search can be seen in the video below."}, {"post_id": 10748, "ts": "2026-06-17T17:14:41Z", "hours": 2.1597, "text": "I finished up mocha download , which surprisingly does a bit more than simply downloading files. The first thing it does is well… download the file. This is a bit more complicated than it seems though, since we need to identify the right file to download based on cpu architecture. Hence the very cursed JSON parsing I had to create. After downloading a file, we also do a hash check. We support the 4 types of file hashes which scoop support, those being sha256 , sha512 , md5 and sha1 . Currently files get downloaded to the $MOCHA_DIR/cache directory like in scoop, however we don’t actually check if there’s anything cached which can lead to repeated downloads. That’s something I’ll need to fix later on"}, {"post_id": 10131, "ts": "2026-06-16T18:54:22Z", "hours": 1.4081, "text": "I was working on the mocha download command so I can sort out fetching files, and during it I realized my current app format makes things a bit weird. mocha cat previously took in a flag for bucket through -b and a name. Scoop on the other hand uses an application reference in the format bucket/name@version . Scoop’s format is really important for downloads and installs, so it didn’t make sense to not standardize it between mocha download and mocha cat . Hence this shorter devlog! See the video below for the new usage (version numbers are ignored for mocha cat )."}, {"post_id": 10004, "ts": "2026-06-16T15:21:57Z", "hours": 2.9753, "text": "I did a bit of refactoring to split the core functionality from the command files. This means that the code for downloading and deleting buckets is separated from the code for the various commands. I’m doing this primarily for better code organization, and also to prevent import cycles. I also finished up the config system I mentioned last time. It’ll be one of the bigger improvements over scoop, which has a basic set of configuration options. TOML was the obvious choice for the config format since it is really easy to read and write. I made sure that you can put it in any of the standard locations, such as %APPDATA% and .config or in $MOCHA_DIR . Running mocha config will open the configuration in your preferred app, and also generate the default config if a configuration hasn’t been detected in any of the valid locations. Currently the configuration can be used to make mocha cat run an external program for printing manifests to stdout . See the video below for an example using bat"}, {"post_id": 8826, "ts": "2026-06-14T17:52:54Z", "hours": 2.6147, "text": "So this is a spot where I think the improvements over scoop start becoming really apparent. The scoop cat command simply prints an app’s manifest to console. However due to the long startup time of PowerShell scripts (scoop is written in PowerShell) basic stuff like scoop cat takes a second. mocha cat on the other hand is nearly instantaneous since it’s a compiled binary with almost 0 startup time. You can see how this plays out in real usage in the video below. I also half baked a config system, but it’s not finished so I’ll talk about that in the next devlog."}, {"post_id": 8586, "ts": "2026-06-14T08:48:35Z", "hours": 2.85, "text": "I finished off the remaining mocha bucket subcommands, those being add , rm and list . These commands manage “buckets” which are pretty much just package sources. mocha bucket add uses git to clone the relevant bucket into the [MOCHA_DIR]/buckets directory. By default MOCHA_DIR is [USER]/mocha mocha bucket list simply loops over the [MOCHA_DIR]/buckets directory and gets relevant info for each bucket. mocha bucket rm removes a bucket by just deleting the folder containing the bucket. For example, removing the main bucket deletes [MOCHA_DIR]/buckets/main"}, {"post_id": 8208, "ts": "2026-06-13T17:32:25Z", "hours": 2.0261, "text": "I started off with something a bit simple: mocha bucket known The known bucket list in scoop is a list of buckets which are known by the package manager in advance. These buckets don’t require the full URL to be used when using scoop bucket sub-commands. For example instead of running scoop bucket add https://github.com/ScoopInstaller/Main you can instead run scoop bucket add main As seen in the video below, mocha bucket known doesn’t do much. First it downloads buckets.json if it doesn’t exist. Then it parses the json and outputs it to console."}]...
|
Title: mocha by @Glitchy | Stardance
Devlogs:
I s Title: mocha by @Glitchy | Stardance
Devlogs:
I started off with something a bit simple: mocha bucket known The known bucket list in scoop is a list of buckets which are known by the package manager in advance. These buckets don’t require the full URL to be used when using scoop bucket sub-commands. For example instead of running scoop bucket add https://github.com/ScoopInstaller/Main you can instead run scoop bucket add main As seen in the video below, mocha bucket known doesn’t do much. First it downloads buckets.json if it doesn’t exist. Then it parses the json and outputs it to console.
I finished off the remaining mocha bucket subcommands, those being add , rm and list . These commands manage “buckets” which are pretty much just package sources. mocha bucket add uses git to clone the relevant bucket into the [MOCHA_DIR]/buckets directory. By default MOCHA_DIR is [USER]/mocha mocha bucket list simply loops over the [MOCHA_DIR]/buckets directory and gets relevant info for each bucket. mocha bucket rm removes a bucket by just deleting the folder containing the bucket. For example, removing the main bucket deletes [MOCHA_DIR]/buckets/main
So this is a spot where I think the improvements over scoop start becoming really apparent. The scoop cat command simply prints an app’s manifest to console. However due to the long startup time of PowerShell scripts (scoop is written in PowerShell) basic stuff like scoop cat takes a second. mocha cat on the other hand is nearly instantaneous since it’s a compiled binary with almost 0 startup time. You can see how this plays out in real usage in the video below. I also half baked a config system, but it’s not finished so I’ll talk about that in the next devlog.
I did a bit of refactoring to split the core functionality from the command files. This means that the code for downloading and deleting buckets is separated from the code for the various commands. I’m doing this primarily for better code organization, and also to prevent import cycles. I also finished up the config system I mentioned last time. It’ll be one of the bigger improvements over scoop, which has a basic set of configuration options. TOML was the obvious choice for the config format since it is really easy to read and write. I made sure that you can put it in any of the standard locations, such as %APPDATA% and .config or in $MOCHA_DIR . Running mocha config will open the configuration in your preferred app, and also generate the default config if a configuration hasn’t been detected in any of the valid locations. Currently the configuration can be used to make mocha cat run an external program for printing manifests to stdout . See the video below for an example using bat
I was working on the mocha download command so I can sort out fetching files, and during it I realized my current app format makes things a bit weird. mocha cat previously took in a flag for bucket through -b and a name. Scoop on the other hand uses an application reference in the format bucket/name@version . Scoop’s format is really important for downloads and installs, so it didn’t make sense to not standardize it between mocha download and mocha cat . Hence this shorter devlog! See the video below for the new usage (version numbers are ignored for mocha cat ).
I finished up mocha download , which surprisingly does a bit more than simply downloading files. The first thing it does is well… download the file. This is a bit more complicated than it seems though, since we need to identify the right file to download based on cpu architecture. Hence the very cursed JSON parsing I had to create. After downloading a file, we also do a hash check. We support the 4 types of file hashes which scoop support, those being sha256 , sha512 , md5 and sha1 . Currently files get downloaded to the $MOCHA_DIR/cache directory like in scoop, however we don’t actually check if there’s anything cached which can lead to repeated downloads. That’s something I’ll need to fix later on
Fuzzy search is really really good. While implementing mocha search I noticed the results returned by scoop search were in alphabetical order, which doesn’t make a lot of sense. If I do scoop search git the first result should probably be git As a result my implementation of search uses github.com/sahilm/fuzzy which is a small library which provides a fuzzy search implementation. Scoop also checks for binary name matches, e.g. package biodiff can provide a binary called git-biodiff and show up in search results. I decided to remove this for now, since I personally find it a bit unnecessary. scoop search also lists all search results, which is okay when results are sorted alphabetically but doesn’t make sense when searches are relevance based. Therefore, by default mocha search will list exact matches plus the 20 most relevant search results. This can be overridden by the --count argument, where setting it to 0 displays all results. A demonstration of mocha search vs scoop search can be seen in the video below.
mocha cache is a simple command. It shows you what files are currently in $MOCHA_DIR/cache directory and it clears them out. One thing I noticed was that scoop cache show actually displays raw bytes instead of human readable file sizes for each cache entry, which is a bit odd since the total they display is human readable. Therefore I made my implementation mocha cache list display human readable sizes since that’s a more reasonable default.
Shims are simple in concept, complicated in reality. So essentially a shim in mocha is just an executable which calls another executable. It’s similar to a shortcut in that sense, except it shows up in $PATH Thankfully the scoop project already has a repository with 4 different implementations for the shim binary, so I can just have mocha shim download one of those binaries. The complicated part was the PE Subsystem. The PE subsystem is basically a bit of info in each binary which tells Windows whether it’s a console application, or a GUI application. We need to set the PE subsystem of the shim exe to the PE subsystem of the binary we are calling for Windows to execute the binary properly. Hence I need to read and write raw binary data. All of this is just the implementation for exe shims. Scoop itself contains implementations for .bat/.cmd , .ps1 , .jar , .py and linux binaries , all of which have wildly different implementations compared to .exe shims. The video below shows the working set of mocha shim commands (those being add , remove and list ).
Spent a bit longer between devlogs this time, but it was worth it. So I realized the error messages were really bad. I was pretty much just passing errors up the call stack without adding any context, which isn’t great since it means our error messages will be useless to people reading them I therefore went through every single file of the codebase and wrote good error messages which add a bit of context every time we pass it up the call stack. I also did a bit of refactoring where I thought it would be worth it. For example in the shim module I now set the PE subsystem of the shim binary while it’s in memory instead of writing to disk twice. A few good examples of what the new error messages look like can be seen in the video below.
mocha update is another command which does very little but is very important. All it does is update the known_buckets file, and run git pull on all added buckets to update them. It can also update just the buckets you specify if you pass in an argument. I do need to improve the output of the command since it outputs raw git right now, but at least it’s functional. See the demo below.
Huge milestone!!! I’ve gotten mocha install working for very basic apps! This means the entire process of downloading a file, then extracting it, then creating a junction and finally creating a shim now works for basic pieces of software! So in terms of what I actually did this devlog, I added cache hits to the download command since it’s relevant to the install command. I then implemented the aforementioned .zip extraction and junction creation. Then all that was left was a bit of orchestration, getting everything to work together properly. See a working install of innounp using mocha install below!
Before working on more features and expanding the amount of apps mocha actually supports I wanted to go through the codebase and do a lot of cleanup since the codebase is quite messy. There are silly mistakes in some files and bad implementations in others. Hence the time I spent during this period was focused on moving code to where it should be and cleaning up some edge cases, specifically related to the bucket , config and shim modules. A good example of this is moving the code to get the active config to the config module instead of leaving it in main.go . Next up will be refactoring the commands , fileops , and manifest modules. I don’t have much to show so I figured I would present a feature I added but didn’t show earlier: the ability to skip cache hits with the --force flag when installing or downloading an app. Some context I forgot to add initially: I renamed the app module to manifest since I felt it was more accurate to what it actually handles scope wise.
Finished up the code cleanup in commands , fileops and manifests . I did catch a few edge cases and some incorrect behavior in the process, which is why I always spend so much time reviewing code. I did use AI to assist with code review because I think it’s an area where AI shines. AI is really good at finding small errors or inconsistencies in the codebase which I probably wouldn’t notice. For example, it identified that the ManifestReferences argument was not a required argument for the download command, which meant no help message was displayed on incorrect usage like the other commands. One big thing I will work on eventually is console output. Right now errors are well formatted but a lot of the time commands just run stuff without providing a lot of insight into what actions they are taking which isn’t great. Even the help menu is pretty useless right now (see the image below). Extra context: A manifest reference is a pointer to an app (e.g. main/ [email protected] )
So I added support for more apps by implementing more extractors. This means in theory any apps which don’t need a pre-install or post-install should work. To be more specific, I handle a few more properties on manifests. Those being extract_dir and innosetup , which inform how an app needs to be installed. I also implement 7zip and innounp as extractors to support more file formats which applications are distributed in. Of course there’s still a lot of work before I consider this ready for public use. I need to create commands for some basic operations like uninstalling, updating and listing apps. I also need to handle shortcuts otherwise GUI apps can’t be accessed from the start menu. Besides that I need to improve the user experience. As you can see in the video below mocha just sort of dumps everything to the console even if it’s not relevant. Help menus are also critical to get working properly.
I finished up mocha uninstall and mocha list , which means you can actually manage installed apps instead of manually deleting them. There’s not much that goes into mocha uninstall . You just need to remove the relevant shims and app directories since the apps that mocha supports are all portable. mocha list is similarly simple. It’s just loops over the directories in $MOCHA_DIR/apps and looks for apps along with the versions installed for each app.
Typically I don’t want to make devlogs for small stuff like this, but this is something I found really cool. So I was working on help messages for all the commands when I realized that mocha bucket list felt a bit slower than pretty much every other command. This is because we need to shell out to git 2 times per bucket, and I had 4 buckets added. While 8 git commands might not sound like a lot, it was enough to make mocha bucket list feel slow. So what I did is I parallelized the metadata fetching through an errgroup . Instead of fetching the metadata for each bucket in order, we fetch the metadata for all 4 buckets simultaneously. This led to a big performance uplift. About 3 times faster than the old version of mocha , and just over 12 times faster than scoop for this operation. See the video below.
As I mentioned in the previous devlog I added good help information to every bit of the CLI. It’s surprisingly difficult to write good help messages which explains everything to users in a few words I also changed the behaviour of the mocha cache clear command to not clear all cache by default. That’s now gated behind the --all flag in order to match scoop a bit more
We now create shortcuts! This means any GUI apps should show up properly in the start menu, just like they do when you install with scoop . All I really had to do was a bit of orchestration since I decided to vendor in an implementation from https://github.com/jxeng/shortcut Besides that I expanded the number of apps that are supported by implementing a bit of code that handle architecture specific bin fields, along with bin fields which store 2D arrays. I also cleared up some of the TODO items. I swapped the junction implementation to an implementation from https://github.com/nyaosorg/go-windows-junction since we were previously shelling out to CLI. That and I added a bit more zip bomb protection For the purposes of the video below I changed the location which shortcuts get put to my desktop. It’ll probably be configurable, and match scoop by putting shortcuts in the startup menu by default
This is going to be the equivalent of 2 devlogs since I thought I made one earlier for persists but I didn’t. New feature! We now handle persist items in order to store data between versions. These are files which are persisted between versions of an app. Lets take git as an example to explain why persist exists. Say you want to make sure your git config isn’t deleted every time you update. The issue with this is that the config file is saved in the version specfic directory. To resolve this we can keep the config in $MOCHA_DIR/persist and then symlink the config to where it needs to be, which is essentially what persist tells us to do. Since we handled persist items last time we can now implement mocha upgrade to update apps. The way scoop handles updates is by first removing anything that references the app, like shortcuts or shims . Then we just follow the install process from scratch. This leaves the old version available in case a user wants to revert versions due to a bug, while also updating to the latest available version. This can be seen in the video below, which shows me updating llama.cpp-hip-radeon .
So I’ve been doing a bit of refactoring, a bit of bug fixing and a bit of optimization. Essentially just polishing mocha before I work on the next feature. Here’s some of the stuff I did: created tests for ParseRefString to validate behavior cache manifest json between info calls since I/O is really slow bumped dependency versions refactored manifest/info.go Besides that I fixed the uninstall flow since it was really bugged after the latest changes. Essentially mocha would uninstall apps with incorrect info. It would also try to remove shims/shortcuts for apps which don’t have any active shims/shortcuts. I then added a bit of logging since the uninstall command didn’t give any user output for whatever reason (i forgot to earlier).
mocha now supports a user defined theme for output colors. In the process I ended up doing a lot of stuff related to the config. First thing I did was swap to fatih/color for colored output, since it handles stuff like colors in command prompt and removing color when output is piped. Then I refactored the config module. Earlier I would pass around a MochaConfiguration object through every function. Now I use a config singleton that’s accessible from any function. Why? Because it means I don’t need to pass the object every time I want to log information. Also means I don’t need to pass mochaDir through almost every function in the codebase. Getting user defined themes was a bit complicated because I needed a good way to handle a default theme so output doesn’t look bad if parsing fails. I handled this by only using the configured theme if every color resolves properly. Otherwise output falls back to the already loaded default theme. Due to this you still get colored output even if there are errors or warning before the configuration and theme is loaded.
I love refactoring!!!! I’ll probably end up spending another 20 hours just on refactoring because it’s so fun!!!! This time around I wanted to refactor the code so that our commands orchestrate stuff instead of the helper functions. For example, pkg.Install would first download a package, then install it, and then link it through shims and shortcuts all by itself. This causes issues because it means error messages become slightly worse, and it creates a class of bugs due to edge cases where we don’t necessarily want this order of orchestration. Hence I did a lot of refactoring in the pkg module. I also ended up adding a way to skip verification of downloads when downloading, installing or updating a package through --skip-verify . It’s a useful option in situations where there is a malformed manifest or simply no hash to begin with.
I’m writing this one right before F1 Qualifying at Spa! Continuing with the trend of some of my recent work, I improved what table outputs look like to be a little bit more readable. We now use proper separators in the form of Unicode Box Drawing Characters . I also made column alignment configurable, which improves legibility for some commands like mocha bucket list and mocha cache show . I’ve attached an image of the scoop and mocha versions of bucket list so you can compare for yourself.
Not sure why I didn’t do this earlier, but I’ve added success messages to commands where it makes sense. Also added a success color to the config so you can change what the success color is. I do still need to improve CLI output quite a bit, but it’s slowly getting there.
My summer break has ended so development is going to be a lot slower from now. I added mocha outdated so you can list outdated apps before upgrading them to a newer version. Besides that I tweaked a lot of stuff related to CLI output. For example I changed search to output one table, and simply outputting exact matches at the top of that table. I also changed a lot of messages which were using LogOutput to LogInfo so they use the correct color and output to stderr and not stdout .
Finally got a bit of time to do a bit of development. First thing I did was remove a field from install.json to match scoop . This means that mocha should be a drop in replacement for existing scoop installs. Then I added partial support for env_set and env_add_path . The main thing I need to do to complete the feature is parse variables and replace them with the appropriate paths. These 2 fields are some of the last manifest fields I need to support besides pre/post (un)install hooks.
Lot of time going into this devlog, but it makes sense since I did do a lot. I did this sweeping refactor of the entire commands module which moved around a lot of code. Essentially each command now gets it’s own directory under the commands module that represents it’s children/parents. For example commands/shim/remove/cmd.go contains code for the mocha shim remove command. Each cmd.go contains a Command struct that has the relevant fields and functions attached to it. This structure just makes things more organized and also means adding test files will be a bit easier since functionality is now isolated. I also sorted out the shim binary. So essentially https://github.com/ScoopInstaller/Shim offers different version of the shim binary which can be installed. Previously I hard coded the code to install cpp v0.1.0 but now users can run mocha shim binary releases to see the options and mocha shim binary setup to install their chosen binary. This also means we actually get the latest releases from GitHub.
Lots of small bug fixes and changes, I’ll just list them out: feat(cmd): allow removal of multiple shims in one execution (f2fae3f) fix(manifest): correctly ignore invalid shortcut entries (6a08478) fix(fileops): use correct registry type (5d5d796) fix(config): seed config with defaults (9dfaaff) fix(cmd): use correct release sources (a2a9ba1) fix(cmd): use bucket from install info (5a9109b) I also added support for more file types being shimmed, which helps a lot with compatibility. The file types are .py , .bat , .cmd , .jar and .ps1 .
I forgot to make a devlog in between so this will be like 2 bigger devlogs. I parallelized bucket updates, which speeds it up quite a bit. This also allowed me to try out parallelism even more, which I plan to apply throughout the CLI later on. I also added configuration options for the runners which mocha shim will use to run certain file types. For example, you can set the python-runner to select the python version that’ll be used to run python scripts that are shimmed. Downloads now have a progress bar, so you don’t need to wonder whether something is happening or not during a long download. Finally env_set is fully supported since I added the relevant variable parsing. This was pretty much just me cleaning out the TODO list before I ship. I also did a lot of smaller bug fixes and refactors as seen below. fix(commands): prevent app installation if already installed (cb27d07) fix(commands): fix config opening with “start” (74f3679) fix(commands): correctly handle non-apps when upgrading (f7419f6) fix: make LogOutput go to Stdout not Stderr (bc10357) fix: handle empty versions correctly (2287da9) fix(pkg): remove correct temp dir (33189b6) fix(shim): warn for unknown shim extension (622c2b4) fix: skip downloads with no hash by default (69d4e35) fix: use correct timeout for downloads (44e527b) fix: drop unnecessary return value from GetExecutableEntries (9fd845c) fix(config): remove unused option (1339971) fix(commands): don’t error for valid results (87c4d6c) refactor(config): rename variables/functions (f253d9d) fix: use unique temp directories (a159e23) refactor: use fmt.Fprintln directly (d2d54bf)
So I wrote a README, added a license (MIT of course) and setup CI/CD so that releases are automatically built and deployed. Honestly I forgot how hard it is to write a good README. You need to get a lot of information through without it looking like a wall of text.
Ships:
I made a package manager for Windows, which is somewhat backwards compatible with scoop packages. To be honest there’s still a lot of work that I want to do, but I have exams and college application coming up soon so I can’t. That’s not to say I’m not happy with the state of the ship. At the very least it has all the core features that a package manager should have, but there are still a lot of bugs which is why this is only v0.0.1. The biggest challenge by far was trying to figure out how Scoop does things internally. A lot of stuff just doesn’t have documentation, so you have to dig through the really messy PowerShell source code....
|
1793008139.1576834
|
1793094539.1576834
|
|
2617
|
Mossy by @dayfit | Stardance
|
dayfit
|
0
|
100.57
|
0
|
[]
|
[{"post_id": 81070, "ts": "202 [{"post_id": 81070, "ts": "2026-10-19T19:09:33Z", "hours": 1.1372, "text": "Devlog 24 After reading and analizing this flow today, I’ve realized that it’s better to keep each vault with it’s own passkey (one leak won’t expose your all keys). Also right now if you have already registered passkey for that vault you can choose to use exising passkey (so it’ll look it up on your device), or create new one (it might overwrite your old one (for same vault)). After reviewing this PR by myself and finding nothing that would make this insecure, I’ve used GPT Astra 6 as well to review it, so now I’m pretty sure that this branch is ready to go on main. See ya!"}, {"post_id": 80793, "ts": "2026-10-18T20:06:37Z", "hours": 4.1375, "text": "Devlog 23 I added one really important thing. Before, Mossy used a 4-digit PIN to unlock the vault (it was used as a wrapping key (after going through HKDF and Argon2)). It was 10,000 combinations. Argon2 made it take longer, but after some time (a few hours), it could be cracked (if someone had your encrypted encryption key (sounds funny :d)). After this change: We use PRF from WebAuthn (really secure stuff) that uses Touch ID, Windows Hello, or Yubico Security Keys (and others) to give deterministic random bytes. Think of it like a random function that remembers what it returned for which argument. Assuming that an attacker would try to brute-force this encryption key, even with 10^18 tries per second, it’d take 1.8 x 10^51 years to crack it (kinda looooong time). Oh, and for those who can’t or don’t wanna use PRF, I’ve added regular passwords. They’re not as good as PRF, but it still takes a really long time to crack those. Those changes are still in an open PR, but it’s 10 PM, and I need to take a closer look at it tomorrow (already did a code review myself, but I’m kinda sleepy, and I’d like to keep y’all secure <3). See ya!"}, {"post_id": 80415, "ts": "2026-10-17T15:50:11Z", "hours": 7.7453, "text": "Devlog 22 Frontend: Added light, dark, and auto themes support (with settings tab!) Settings tab with themes options and links to request new features Added dashboard onboarding to help users setup their vault and add their first password Reworked key synchronization (now users will provide 6-character code instead of 6-digits code (Also it lacks of ambiguous characters like “l” and “I”) Backend: Complete rework of key-sync microservice (HTTP + SSE instead of WebSockets) (so user can access synchronized passwords up to 5 minutes after they are sent) Improved scallability by completely rethinking key-sync flow (that was kinda tricky)"}, {"post_id": 79105, "ts": "2026-10-12T18:01:50Z", "hours": 10.0319, "text": "Devlog 21 Changelogs Frontend: Standarized colors, boders, shadows, and button styles using globals.css system Updated typography: Syne for body text and Geologica for headings Centered headers navigation links Redesigned home page hero Fixed the footer so it stays at the bottom of the page Added leaf decorations on home page Based on feedback (from flavortown) I’ve decided to add some links to docs and instructions on how to set something up. Backend: Added SSE endpoint for live device enrollment updates I am working on delivering some more things before end of stardance. Stay tuned!"}, {"post_id": 70708, "ts": "2026-09-19T17:00:52Z", "hours": 5.3025, "text": "Devlog 20 Here is what happend after last devlog (lots of improvements :D) On frontend: Improved secured passwords chart, so it does only show integer values, centered chart’s line Added total count of passwords chart (as default mode) Added email verification interface Improved recent actions section Removed website icon from recent action card (API was broken, and it didn’t looked good anyway) On backend: Finished and integrated email verification system (verification link and code expires after 15 minutes) Added limits for incorrect codes, resend cooldowns, and hourly email deliveries Added rate limiting to public verification endpoint Emails are sent asynchronously through RabbitMQ That’s all for now. I’ll focus on design consistency & responsiveness for now."}, {"post_id": 65279, "ts": "2026-09-10T09:25:36Z", "hours": 7.6328, "text": "Devlog 19 It’s been a long time from last devlog. Here is changelog: On frontend: Vault loading, refreshing, selection, etc are now centralized in zustand store Removed redundant useVault hook Now user can select vault from dashboard view Added clearer selected-vault indicators and improved keyboard accessibility Made dashboard vault cards presentational and reusable On backend: Fixed critical bug in resource server logic (refresh token could be used as auth token (very bad :c)) Improved and refactored jwt validation & generation Added correct typ claim in JWT tokens Simplified refresh token claims (some were unused or not necessary) Updated Authentication.md documentation Expanded JWT generation, management, and decoder tests Work in progress: Currently I’m working on new feature, central microservice that will handle sending emails to users This is what I got so far: Batched async communication through RabbitMQ Integration with resend and some templates Retry queue with 30 secounds delay Service requeue mail only if something went wrong with sending (429 or 5XX response), if recipient doesn’t exist, there is no requeue Added tests for duplicates, pending commands, successful sends, permanent failures, and retryable failures. See ya!"}, {"post_id": 59672, "ts": "2026-09-01T16:25:07Z", "hours": 1.7078, "text": "Devlog 18 Mock API is finished, now I’m working on frontend design & consistency Changelog Finished Mock API Renamed RippleButton to Button as it’s generic right now Made Button component generic (support for icon, ghost buttons etc) Replaced all buttons with generic Button component Also I adjusted some colors so design is more consistent. See ya!"}, {"post_id": 59001, "ts": "2026-08-31T16:08:03Z", "hours": 7.1164, "text": "Devlog 17 Device manager is now up and running on production! in code review I noticed: some edge cases (mostly related with multi-threading) user could not change accounts (persisted device id was the issue) probably more, but stardance was down so I couldn’t write this devlog Now I’m working on creating Mock API so frontend development will no longer require running real backend. Stay tuned!"}, {"post_id": 46463, "ts": "2026-08-13T18:01:12Z", "hours": 1.7533, "text": "Devlog 16 Finally device manager is ready to go. Refactored frontend side logic for key-sync to work with new API Fixed bugs, improved error handling (so error message is not misleading) Removed .idea folder from repo Introduced mossy-reactor (way to test micro-services with their dependencies without deploying them to main before tests) Now it’s time to work on frontend features + design (typography, colors, globals <– boring stuff ://)"}, {"post_id": 45388, "ts": "2026-08-11T20:21:14Z", "hours": 3.4439, "text": "Devlog 15 I’ve integrated API with frontend, created new tab for managing devices. Fixed some bugs related to interation of cross-microservice communication (maybe I’ll write some integration tests? who knows) I’ve added detection of OS and device type via user agent (using Yauaa library). Now I’ll have to think about how to create good risk-engine when at same time not storing too much user informations (to keep it privacy-first) If you guys have some idea how to do that let me know! To merge this feature to develop branch I need to fix some really minor bugs. see ya!"}, {"post_id": 44650, "ts": "2026-08-10T15:43:24Z", "hours": 9.4775, "text": "Devlog 14 Soo… Recently I saw that there was no way to add new devices (** facepalm **). From last devlog I created nice enrollment system that will require already verified device to accept new one before trusting it. I’ve utilized JWT scopes for that, so client authenticated with enrollment token can only access specific endpoints. All of that probably sounds pretty easy but e g. I didn’t wanted to duplicate existing code, enrollment token is issued by same /login endpoint etc etc. basically it was quite a hustle. Hopefully, next devlog will be about how I integrated API with frontend (cross your fingers!) BTW: test count jumped from 31 to 72 from last devlog so you can see how big is the difference!"}, {"post_id": 34100, "ts": "2026-07-24T16:02:15Z", "hours": 5.6378, "text": "Devlog 13 Device manager is pretty much ready to go to production from API pov (there are some things that I still need to code tho), from last devlog I integrated it with Auth microservice, with each login / session refreshment it’s checked if given device is blocked, if so, Mossy will refuse to provide user new tokens. PS: look at those green tests (so cool)!"}, {"post_id": 29715, "ts": "2026-07-16T20:09:15Z", "hours": 4.5417, "text": "Hello there! From last devlog I’ve managed to add some features for this new Device Trust Microservice. Right now device can be blocked by another device (it will stop this device from access to account) Nonce challenge is working and has really good test coverage (this whole microservice does too) thanks to TDD I’ve finished implementing controllers & their tests It might look like TDD is slowing me down, but my code is getting really mature (each scenario is prepared). For whole process of developing this MS I didn’t opened insomnia even once - and that’s cool, because running tests without running whole MS (and it’s dependencies) is much faster. See ya!"}, {"post_id": 29114, "ts": "2026-07-15T19:34:36Z", "hours": 10.0033, "text": "Hello everyone, For last 10 hours I’ve made major progress on Mossy development. First of all my custom JWKS system got replaced by Spring Boot OAuth2 Resource Server Starter (looong name isn’t it?), it’ll make future maintance & coding much easier. In futher I’m going to migrate it to use Authorization Server Starter to achive full OAuth2 compatibility. Also I’ve been learning how TDD works, and for last 4 hours I’ve been using it during coding, it makes life so much easier! I’m currently working on new feature - Device Manager, it’s really huge feature (I need to refactor existing Device MS), but it’s really exciting, it’ll show you what devices are added to your account & analyze risk of each login (based on your common IP & MAC & OS & some more) it requires me to change old Device Microservice domain to just key-sync. Also I’ll create 2 new microservices - one called Device Trust (I’m working on it currently), it’ll tell my Authentication system to allow login or not (before cryptography was just for key-sync) by using challenge - client’ll receive randomly generated nonce and it’ll have to sign it with it’s key. Then if everything is alright it’ll ask Risk Engine if it should send user an alert or not (in future it might require MFA from client detected as higher risk) This is my biggest project ever Stay tuned!"}, {"post_id": 12018, "ts": "2026-06-19T16:35:36Z", "hours": 1.5044, "text": "Mossy now supports ssh public keys as well Refactored actions in frontend code to achive cleaner code Added validation of ssh keys"}, {"post_id": 11466, "ts": "2026-06-18T18:57:58Z", "hours": 2.0375, "text": "Mossy now supports SSH keys! Old Add Password form got removed, and replaced by new, cleaner one. Also I’m on my way to refactor code, and make lifting of Mossy’s extension UI. Support for public keys, and other SSH specific features will be introduce later, right now, only private key is supported"}, {"post_id": 10739, "ts": "2026-06-17T17:00:53Z", "hours": 2.2661, "text": "Notes system is ready and works like a charm, I had minor problem with JPA while implementing it ( Cascade.ALL ) fixed issue. Notes are encrypted with vault encryption key, so it’s suitable for sensitive data. Next up I’ll implement usage history!"}, {"post_id": 10186, "ts": "2026-06-16T20:00:41Z", "hours": 2.2619, "text": "Now, I’m working on implementing notes for passwords, backend is already ready, and frontend logic is half-way there, probably I’ll finish everything tommorow. Also I’ve made major refactor in vault request handlers logic by creating AbstractVaultRequestHandler to keep boilerplate-code in one place."}, {"post_id": 10021, "ts": "2026-06-16T15:59:05Z", "hours": 0.8125, "text": "Mossy’s search engine works like a charm!"}, {"post_id": 9322, "ts": "2026-06-15T17:15:42Z", "hours": 0.7514, "text": "Currently, I’m working on a search engine for Mossy using Fuse.js. There are still a few things to implement, such as the UI for query search, and some bugs in the tag search logic to fix."}, {"post_id": 8271, "ts": "2026-06-13T19:19:54Z", "hours": 2.9025, "text": "I’ve finaly finished system of managing tags! I really like how it turned out. Next up I’ll work on searching and filtering passwords!"}, {"post_id": 5828, "ts": "2026-06-09T19:26:39Z", "hours": 2.2906, "text": "Whole tag system is ready on backend, currently I’m working on integrating frontend with API in nice way. stay tuned !!!"}, {"post_id": 5145, "ts": "2026-06-08T20:42:33Z", "hours": 4.7406, "text": "I’ve created vault <—> backend communication for adding, assigning, and getting tags. Also adding logic is ready on frontend. Whole system ’ll be ready by tommorow 😱"}, {"post_id": 2856, "ts": "2026-06-05T18:23:25Z", "hours": 1.3331, "text": "Currently, I’m writing tag management system, that will include CRUD on tags, searching for passwords with tags. Adding tags already works! Also I’ve made really nice roadmap of Mossy Development!"}]...
|
Title: Mossy by @dayfit | Stardance
Devlogs:
Curr Title: Mossy by @dayfit | Stardance
Devlogs:
Currently, I’m writing tag management system, that will include CRUD on tags, searching for passwords with tags. Adding tags already works! Also I’ve made really nice roadmap of Mossy Development!
I’ve created vault <—> backend communication for adding, assigning, and getting tags. Also adding logic is ready on frontend. Whole system ’ll be ready by tommorow 😱
Whole tag system is ready on backend, currently I’m working on integrating frontend with API in nice way. stay tuned !!!
I’ve finaly finished system of managing tags! I really like how it turned out. Next up I’ll work on searching and filtering passwords!
Currently, I’m working on a search engine for Mossy using Fuse.js. There are still a few things to implement, such as the UI for query search, and some bugs in the tag search logic to fix.
Mossy’s search engine works like a charm!
Now, I’m working on implementing notes for passwords, backend is already ready, and frontend logic is half-way there, probably I’ll finish everything tommorow. Also I’ve made major refactor in vault request handlers logic by creating AbstractVaultRequestHandler to keep boilerplate-code in one place.
Notes system is ready and works like a charm, I had minor problem with JPA while implementing it ( Cascade.ALL ) fixed issue. Notes are encrypted with vault encryption key, so it’s suitable for sensitive data. Next up I’ll implement usage history!
Mossy now supports SSH keys! Old Add Password form got removed, and replaced by new, cleaner one. Also I’m on my way to refactor code, and make lifting of Mossy’s extension UI. Support for public keys, and other SSH specific features will be introduce later, right now, only private key is supported
Mossy now supports ssh public keys as well Refactored actions in frontend code to achive cleaner code Added validation of ssh keys
Hello everyone, For last 10 hours I’ve made major progress on Mossy development. First of all my custom JWKS system got replaced by Spring Boot OAuth2 Resource Server Starter (looong name isn’t it?), it’ll make future maintance & coding much easier. In futher I’m going to migrate it to use Authorization Server Starter to achive full OAuth2 compatibility. Also I’ve been learning how TDD works, and for last 4 hours I’ve been using it during coding, it makes life so much easier! I’m currently working on new feature - Device Manager, it’s really huge feature (I need to refactor existing Device MS), but it’s really exciting, it’ll show you what devices are added to your account & analyze risk of each login (based on your common IP & MAC & OS & some more) it requires me to change old Device Microservice domain to just key-sync. Also I’ll create 2 new microservices - one called Device Trust (I’m working on it currently), it’ll tell my Authentication system to allow login or not (before cryptography was just for key-sync) by using challenge - client’ll receive randomly generated nonce and it’ll have to sign it with it’s key. Then if everything is alright it’ll ask Risk Engine if it should send user an alert or not (in future it might require MFA from client detected as higher risk) This is my biggest project ever Stay tuned!
Hello there! From last devlog I’ve managed to add some features for this new Device Trust Microservice. Right now device can be blocked by another device (it will stop this device from access to account) Nonce challenge is working and has really good test coverage (this whole microservice does too) thanks to TDD I’ve finished implementing controllers & their tests It might look like TDD is slowing me down, but my code is getting really mature (each scenario is prepared). For whole process of developing this MS I didn’t opened insomnia even once - and that’s cool, because running tests without running whole MS (and it’s dependencies) is much faster. See ya!
Devlog 13 Device manager is pretty much ready to go to production from API pov (there are some things that I still need to code tho), from last devlog I integrated it with Auth microservice, with each login / session refreshment it’s checked if given device is blocked, if so, Mossy will refuse to provide user new tokens. PS: look at those green tests (so cool)!
Devlog 14 Soo… Recently I saw that there was no way to add new devices (** facepalm **). From last devlog I created nice enrollment system that will require already verified device to accept new one before trusting it. I’ve utilized JWT scopes for that, so client authenticated with enrollment token can only access specific endpoints. All of that probably sounds pretty easy but e g. I didn’t wanted to duplicate existing code, enrollment token is issued by same /login endpoint etc etc. basically it was quite a hustle. Hopefully, next devlog will be about how I integrated API with frontend (cross your fingers!) BTW: test count jumped from 31 to 72 from last devlog so you can see how big is the difference!
Devlog 15 I’ve integrated API with frontend, created new tab for managing devices. Fixed some bugs related to interation of cross-microservice communication (maybe I’ll write some integration tests? who knows) I’ve added detection of OS and device type via user agent (using Yauaa library). Now I’ll have to think about how to create good risk-engine when at same time not storing too much user informations (to keep it privacy-first) If you guys have some idea how to do that let me know! To merge this feature to develop branch I need to fix some really minor bugs. see ya!
Devlog 16 Finally device manager is ready to go. Refactored frontend side logic for key-sync to work with new API Fixed bugs, improved error handling (so error message is not misleading) Removed .idea folder from repo Introduced mossy-reactor (way to test micro-services with their dependencies without deploying them to main before tests) Now it’s time to work on frontend features + design (typography, colors, globals <– boring stuff ://)
Devlog 17 Device manager is now up and running on production! in code review I noticed: some edge cases (mostly related with multi-threading) user could not change accounts (persisted device id was the issue) probably more, but stardance was down so I couldn’t write this devlog Now I’m working on creating Mock API so frontend development will no longer require running real backend. Stay tuned!
Devlog 18 Mock API is finished, now I’m working on frontend design & consistency Changelog Finished Mock API Renamed RippleButton to Button as it’s generic right now Made Button component generic (support for icon, ghost buttons etc) Replaced all buttons with generic Button component Also I adjusted some colors so design is more consistent. See ya!
Devlog 19 It’s been a long time from last devlog. Here is changelog: On frontend: Vault loading, refreshing, selection, etc are now centralized in zustand store Removed redundant useVault hook Now user can select vault from dashboard view Added clearer selected-vault indicators and improved keyboard accessibility Made dashboard vault cards presentational and reusable On backend: Fixed critical bug in resource server logic (refresh token could be used as auth token (very bad :c)) Improved and refactored jwt validation & generation Added correct typ claim in JWT tokens Simplified refresh token claims (some were unused or not necessary) Updated Authentication.md documentation Expanded JWT generation, management, and decoder tests Work in progress: Currently I’m working on new feature, central microservice that will handle sending emails to users This is what I got so far: Batched async communication through RabbitMQ Integration with resend and some templates Retry queue with 30 secounds delay Service requeue mail only if something went wrong with sending (429 or 5XX response), if recipient doesn’t exist, there is no requeue Added tests for duplicates, pending commands, successful sends, permanent failures, and retryable failures. See ya!
Devlog 20 Here is what happend after last devlog (lots of improvements :D) On frontend: Improved secured passwords chart, so it does only show integer values, centered chart’s line Added total count of passwords chart (as default mode) Added email verification interface Improved recent actions section Removed website icon from recent action card (API was broken, and it didn’t looked good anyway) On backend: Finished and integrated email verification system (verification link and code expires after 15 minutes) Added limits for incorrect codes, resend cooldowns, and hourly email deliveries Added rate limiting to public verification endpoint Emails are sent asynchronously through RabbitMQ That’s all for now. I’ll focus on design consistency & responsiveness for now.
Devlog 21 Changelogs Frontend: Standarized colors, boders, shadows, and button styles using globals.css system Updated typography: Syne for body text and Geologica for headings Centered headers navigation links Redesigned home page hero Fixed the footer so it stays at the bottom of the page Added leaf decorations on home page Based on feedback (from flavortown) I’ve decided to add some links to docs and instructions on how to set something up. Backend: Added SSE endpoint for live device enrollment updates I am working on delivering some more things before end of stardance. Stay tuned!
Devlog 22 Frontend: Added light, dark, and auto themes support (with settings tab!) Settings tab with themes options and links to request new features Added dashboard onboarding to help users setup their vault and add their first password Reworked key synchronization (now users will provide 6-character code instead of 6-digits code (Also it lacks of ambiguous characters like “l” and “I”) Backend: Complete rework of key-sync microservice (HTTP + SSE instead of WebSockets) (so user can access synchronized passwords up to 5 minutes after they are sent) Improved scallability by completely rethinking key-sync flow (that was kinda tricky)
Devlog 23 I added one really important thing. Before, Mossy used a 4-digit PIN to unlock the vault (it was used as a wrapping key (after going through HKDF and Argon2)). It was 10,000 combinations. Argon2 made it take longer, but after some time (a few hours), it could be cracked (if someone had your encrypted encryption key (sounds funny :d)). After this change: We use PRF from WebAuthn (really secure stuff) that uses Touch ID, Windows Hello, or Yubico Security Keys (and others) to give deterministic random bytes. Think of it like a random function that remembers what it returned for which argument. Assuming that an attacker would try to brute-force this encryption key, even with 10^18 tries per second, it’d take 1.8 x 10^51 years to crack it (kinda looooong time). Oh, and for those who can’t or don’t wanna use PRF, I’ve added regular passwords. They’re not as good as PRF, but it still takes a really long time to crack those. Those changes are still in an open PR, but it’s 10 PM, and I need to take a closer look at it tomorrow (already did a code review myself, but I’m kinda sleepy, and I’d like to keep y’all secure <3). See ya!
Devlog 24 After reading and analizing this flow today, I’ve realized that it’s better to keep each vault with it’s own passkey (one leak won’t expose your all keys). Also right now if you have already registered passkey for that vault you can choose to use exising passkey (so it’ll look it up on your device), or create new one (it might overwrite your old one (for same vault)). After reviewing this PR by myself and finding nothing that would make this insecure, I’ve used GPT Astra 6 as well to review it, so now I’m pretty sure that this branch is ready to go on main. See ya!...
|
1792486412.4775856
|
1793091212.4775856
|
|
65850
|
blockers by @evmaagca | Stardance
|
evmaagca
|
1
|
100.52
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-25T23:18:09Z", "hours": 100.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "blockers is a top-down game made with Godot and GDScript where players control a knight exploring dark environments, fighting enemies with a spear, and using a flashlight to survive. I’m especially proud of creating 15 levels, developing the combat and flashlight systems, designing the enemies, and implementing the UI, save system, and achievements. This project has helped me improve my godot coding skills, and I hope to use what I’ve learned to create more games in the future! Thank you in advance to all the reviewers! features 15 levels that get harder title screen with buttons for extras, levels, achievements, and settings a spear for fighting enemies flashlight system that drains energy while exploring dark areas health and flashlight energy systems power switches that must be activated to progress through certain levels vending machines that restore flashlight energy heart pickups that restore health regular and electric drone enemies with different challenges knockback and enemy death animations achievement system that tracks player accomplishments level progression and save system", "repo": "https://github.com/evacoffee/blockers", "demo": "https://evmaagca.itch.io/blockers"}]...
|
[{"post_id": 83097, "ts": "202 [{"post_id": 83097, "ts": "2026-10-26T21:29:03Z", "hours": 0.5208, "text": "hi so for all those who are going to review this my level select is not working right now so I would appreciate it if those who are looking at this just ignore that feature for right now, I am working on it and hopefully it will be done soon! so sorry 😔🙏"}, {"post_id": 82827, "ts": "2026-10-25T23:15:32Z", "hours": 7.0211, "text": "devlog #18 (last one! ) : made a last ditched attempt to fix the levelselect! (again spent an embarrassing amount of time doing this) (didnt work ), made some last additions to the scripts like lights flashing etc"}, {"post_id": 82501, "ts": "2026-10-25T01:16:22Z", "hours": 5.6831, "text": "devlog #17 : added another level, fixed a powerswitch issue/bug 🐛 , added more notes!, made he trashcan animation way smother with tweens, added the final level! (wont show the final levels to not spoil)"}, {"post_id": 82141, "ts": "2026-10-24T02:42:27Z", "hours": 9.3342, "text": "devlog #16 : made when you press achievement popup it pauses game , another 2 levels!! (trying to maybe get to around 20? im running out of ideas tho ), worked on levelselect for way more trying to fix the thing for mobile (still hasn’t worked )"}, {"post_id": 81675, "ts": "2026-10-22T00:47:22Z", "hours": 9.0367, "text": "devlog #15 : made 4 new levels!! (took forever ), fixed shader script because it always made the duplicated drones not show up , fixed the titlescreen script so it has better ui 🎨 , and fixed a bug in the titlescreen load"}, {"post_id": 81132, "ts": "2026-10-20T00:45:18Z", "hours": 9.955, "text": "devlog #14 : added sparks when spear hits drone, fixed bugs in achivement manager, added dissolve shader (had to search for a tutorial for this ) for both drones (made it kinda break apart piece by piece), fixed multiple scripts (like all of them took around 4 ish hours) as the code was bothering me"}, {"post_id": 80277, "ts": "2026-10-17T02:38:47Z", "hours": 9.5736, "text": "devlog #13 : added achievements ⭐ !!, added achievements into the title screen, changed level button to extra button then put that into there, changed the heart charge ❤️ , added/changed the regdrone and elecdrone scripts to flicker and disappear when dying also created a video for this!!"}, {"post_id": 79418, "ts": "2026-10-13T21:46:58Z", "hours": 6.2628, "text": "devlog #12 : added dust when moving with player flashlight, hearts drop sometimes when enemy dies, fixed issue when player died (took like 2 hours ), fixed bug with mobile ver"}, {"post_id": 78869, "ts": "2026-10-11T20:18:22Z", "hours": 8.56, "text": "devlog #11 : added a fade for the hearts, tried again to fix the levellist , added a glow around the vending machine so that if your light turns off you can find a vending machine , added small dust particles, added another level"}, {"post_id": 78216, "ts": "2026-10-10T00:25:52Z", "hours": 8.6956, "text": "devlog #10 : made 2 new levels, redid some of the notes and added more, and tried to fix a bug I think I genuinely spent like 7 hours straight just trying to debug this one issue with my script that was making the levellist not showing up on mobile (ps it didnt even work )"}, {"post_id": 77448, "ts": "2026-10-07T01:32:20Z", "hours": 3.3167, "text": "devlog #9: made uh the levelselect (which took forever btw genuinely worst experience of my entire existence of life), level 5 made, levelselect bg with canva 🐐 , also side note not with the actual time of godot but I figured out how to view my projects on my phone!!"}, {"post_id": 77182, "ts": "2026-10-05T23:32:14Z", "hours": 2.8656, "text": "devlog #8 : fixed the switches script, added esc button/esc box, made level 3+4!"}, {"post_id": 76894, "ts": "2026-10-04T23:45:23Z", "hours": 4.1417, "text": "devlog #7 : added mobile!!! + used canva 🐐 for this!, changed title music, added transition between titlescreen and actual game"}, {"post_id": 76003, "ts": "2026-10-02T00:41:57Z", "hours": 3.655, "text": "devlog #6 : added a trashcan = heart pickups, made level 2, added extra noises (+ redid some of the volume of them), made the start of the titlescreen + the buttons for it, redid some bugs ( bro took me like 40 minutes of one and I genually feel like death after )"}, {"post_id": 75030, "ts": "2026-09-28T22:22:37Z", "hours": 1.115, "text": "devlog #5 : made the continuation of the level one, updated music, added another blocker (the drones)!"}, {"post_id": 74623, "ts": "2026-09-27T19:51:56Z", "hours": 5.64, "text": "devlog #4 : added the flashlight on and off function, made the vending machines refill the light, made the light bar, made all health, made the potholes + the destinations (still debugging), added better music/different sounds"}, {"post_id": 74033, "ts": "2026-09-26T15:50:20Z", "hours": 5.1569, "text": "devlog #1-3 : added collision tiles, player movement, bg music, decorations, and the start of enemies (so sorry in advance for the bad devlogs)"}]...
|
Title: blockers by @evmaagca | Stardance
Devlogs: Title: blockers by @evmaagca | Stardance
Devlogs:
devlog #1-3 : added collision tiles, player movement, bg music, decorations, and the start of enemies (so sorry in advance for the bad devlogs)
devlog #4 : added the flashlight on and off function, made the vending machines refill the light, made the light bar, made all health, made the potholes + the destinations (still debugging), added better music/different sounds
devlog #5 : made the continuation of the level one, updated music, added another blocker (the drones)!
devlog #6 : added a trashcan = heart pickups, made level 2, added extra noises (+ redid some of the volume of them), made the start of the titlescreen + the buttons for it, redid some bugs ( bro took me like 40 minutes of one and I genually feel like death after )
devlog #7 : added mobile!!! + used canva 🐐 for this!, changed title music, added transition between titlescreen and actual game
devlog #8 : fixed the switches script, added esc button/esc box, made level 3+4!
devlog #9: made uh the levelselect (which took forever btw genuinely worst experience of my entire existence of life), level 5 made, levelselect bg with canva 🐐 , also side note not with the actual time of godot but I figured out how to view my projects on my phone!!
devlog #10 : made 2 new levels, redid some of the notes and added more, and tried to fix a bug I think I genuinely spent like 7 hours straight just trying to debug this one issue with my script that was making the levellist not showing up on mobile (ps it didnt even work )
devlog #11 : added a fade for the hearts, tried again to fix the levellist , added a glow around the vending machine so that if your light turns off you can find a vending machine , added small dust particles, added another level
devlog #12 : added dust when moving with player flashlight, hearts drop sometimes when enemy dies, fixed issue when player died (took like 2 hours ), fixed bug with mobile ver
devlog #13 : added achievements ⭐ !!, added achievements into the title screen, changed level button to extra button then put that into there, changed the heart charge ❤️ , added/changed the regdrone and elecdrone scripts to flicker and disappear when dying also created a video for this!!
devlog #14 : added sparks when spear hits drone, fixed bugs in achivement manager, added dissolve shader (had to search for a tutorial for this ) for both drones (made it kinda break apart piece by piece), fixed multiple scripts (like all of them took around 4 ish hours) as the code was bothering me
devlog #15 : made 4 new levels!! (took forever ), fixed shader script because it always made the duplicated drones not show up , fixed the titlescreen script so it has better ui 🎨 , and fixed a bug in the titlescreen load
devlog #16 : made when you press achievement popup it pauses game , another 2 levels!! (trying to maybe get to around 20? im running out of ideas tho ), worked on levelselect for way more trying to fix the thing for mobile (still hasn’t worked )
devlog #17 : added another level, fixed a powerswitch issue/bug 🐛 , added more notes!, made he trashcan animation way smother with tweens, added the final level! (wont show the final levels to not spoil)
devlog #18 (last one! ) : made a last ditched attempt to fix the levelselect! (again spent an embarrassing amount of time doing this) (didnt work ), made some last additions to the scripts like lights flashing etc
hi so for all those who are going to review this my level select is not working right now so I would appreciate it if those who are looking at this just ignore that feature for right now, I am working on it and hopefully it will be done soon! so sorry 😔🙏
Ships:
blockers is a top-down game made with Godot and GDScript where players control a knight exploring dark environments, fighting enemies with a spear, and using a flashlight to survive. I’m especially proud of creating 15 levels, developing the combat and flashlight systems, designing the enemies, and implementing the UI, save system, and achievements. This project has helped me improve my godot coding skills, and I hope to use what I’ve learned to create more games in the future! Thank you in advance to all the reviewers! features 15 levels that get harder title screen with buttons for extras, levels, achievements, and settings a spear for fighting enemies flashlight system that drains energy while exploring dark areas health and flashlight energy systems power switches that must be activated to progress through certain levels vending machines that restore flashlight energy heart pickups that restore health regular and electric drone enemies with different challenges knockback and enemy death animations achievement system that tracks player accomplishments level progression and save system...
|
1793091193.4322348
|
1793177593.4322348
|
|
21776
|
python Terminal multitool by @robopugo | Stardance
|
robopugo
|
0
|
100.46
|
0
|
[]
|
[{"post_id": 74687, "ts": "202 [{"post_id": 74687, "ts": "2026-09-28T00:14:07Z", "hours": 2.3161, "text": "added some file based commands (ls, pwd, cd.) to the repl, and created this cool colorized ascii img shower, as shown in img. Also finally reached 100hrs on this project, yipee!, some stats: over 100 functions, and over 4.5k lines (only 600 are empty), 57 imports, rougley 50% of functions have doc-strings and typed args, and over 3k word of documentation in the code. 19 classes. All in python."}, {"post_id": 73695, "ts": "2026-09-25T18:36:24Z", "hours": 0.8197, "text": "A pretty easy feature that makes it significantly smoother and better. For example –A which doesn’t clear the screen, nor prints the help text. Overall pretty good QOL feature for the repl. (python)"}, {"post_id": 72941, "ts": "2026-09-24T02:42:33Z", "hours": 1.0939, "text": "added finishing touches to the markdown renderer. And went ahead and made another cool func that shows the dependencies of a function. Which was a pretty fun challenge. Also good news stardance is being extended to oct. 31. What team are you? (python)"}, {"post_id": 72462, "ts": "2026-09-23T00:52:34Z", "hours": 1.6061, "text": "I got themes working for the markdown renderer, but I got to lock in on everything else since Stardance is almost over. (video is bright.) (python)"}, {"post_id": 71380, "ts": "2026-09-20T18:32:51Z", "hours": 2.2656, "text": "made a readme veiwer similar to glow, that is fully customizable. supports h1-h6 p, lists, quotes, bold, italic, crossed, code inline, code blocks, and highlighted text. Main challenge was doing it without regex’s. (python)"}, {"post_id": 70697, "ts": "2026-09-19T16:33:43Z", "hours": 2.5603, "text": "created this cool little form that you can fill out for a function to auto generate a docstring for it by default coppies it to clipboard but you can also have it auto write it in file. (i will admit i had to use some ai to figure out how to get it to write in file) (python)"}, {"post_id": 69297, "ts": "2026-09-16T19:21:29Z", "hours": 2.0033, "text": "added a favorites menu, and the ability to add functions to the favorites. Also added .ax and .ay . (python)"}, {"post_id": 66142, "ts": "2026-09-11T19:27:48Z", "hours": 0.6558, "text": ".mx was a fun new challenge after my little break from the tool, like .my it shows multiple docs, also supports the multi run, next feature to add is text warping. Hopefully I can get in 5hrs soon so i can get the limited stickers. :) (python)"}, {"post_id": 65530, "ts": "2026-09-10T18:44:46Z", "hours": 0.5775, "text": "it looks a lot better in the terminal but i made a big clock widget."}, {"post_id": 65130, "ts": "2026-09-10T01:49:46Z", "hours": 0.5306, "text": "small devlog, so one thing about my project is that it’s built to help others make tui’s, but not all projects are in python, so how did I learn to make this well I started here: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 , ANSI escape codes are just cli terminal coloring, add in some unicode and you got a cool stylized thingy. The img is an example of something I quickly built to showcase how much tui’s improve visuals, check it out here: https://codehs.com/sandbox/robopugo/gfojafowj/run . It’s still in python. Just wanted to share how I got introduced to Tui’s since I figured others might also want to find a way to get started."}, {"post_id": 64507, "ts": "2026-09-08T23:21:15Z", "hours": 8.0453, "text": "[this will be a longer devlog]. So what are these 2 things, and what do they have to do with stylized docs, glad you asked. After designing a stylized help func, I made a main menu / repl that shows you the names of all the functions and you can type the name to see its stylized doc card. The first img shows all of the names of the functions in my module currently, the second shows all of the helper funcs / commands in the repl. (not all are implemented, but most are). The main features I like are that it’s stateful with a back command, and the .run command which lets you run the example code right there. I uploaded a long form video to my YT channel if you want to see it in action: https://youtu.be/niP3qDd2KkY"}, {"post_id": 53249, "ts": "2026-08-23T18:08:17Z", "hours": 1.6172, "text": "made the border a gradient, which honestly, just looks really good. Now going to work on the menu."}, {"post_id": 53086, "ts": "2026-08-23T14:46:16Z", "hours": 4.8411, "text": "Hello, been a while, but I’m finally happy with it, so some context: python has these things called doc-strings which are basically special comments in a function that explain what the function does and how to use it, you can see this with the help() function. I wanted to make my own version, but stylized, and i succeeded, and mine is pretty dynamic. How it works: it uses a list of headers to make sections and then styles them based on indentation. (also shows color palate in bottom right). Planning on making some sort of menu to easily read these."}, {"post_id": 48254, "ts": "2026-08-16T15:40:00Z", "hours": 1.1075, "text": "started to mess with fonts and sadly a lot of fonts don’t support “\\n”, but this one does, and i used wrap to apply the 4 color gradient to it, planning on working on adding the random text, and maybe another loading throbber of sorts. (python)"}, {"post_id": 46636, "ts": "2026-08-14T01:06:04Z", "hours": 1.2514, "text": "added a wrap func that is used to dynamically apply colors to strings, allowing you to easily print text that’s color is a gradient. (python)"}, {"post_id": 44356, "ts": "2026-08-10T02:03:15Z", "hours": 0.4517, "text": "I haven’t really documented this on star dance, but you can use ascii (or any color type or set of symbols, or even just data) in the gradients instead of rgb…"}, {"post_id": 44331, "ts": "2026-08-10T00:48:40Z", "hours": 2.0283, "text": "made a multi positional interpolated gradient in python, simply put, a gradient where you can have any amount of colors and you can pick their position."}, {"post_id": 43027, "ts": "2026-08-08T02:27:09Z", "hours": 5.0992, "text": "a terminal 4 color gradient that uses bilinear interpolation and ANSI. Also made a 1d gradient tool, and both can be used for data gradients. (python)"}, {"post_id": 41393, "ts": "2026-08-05T16:03:38Z", "hours": 4.8672, "text": "donut i made that uses ANSI instead of Ascii to render. (python)"}, {"post_id": 40451, "ts": "2026-08-03T23:35:41Z", "hours": 0.8589, "text": "I think i speak computer now… reading terminal chars and converting to rgb, was easy…."}, {"post_id": 40420, "ts": "2026-08-03T22:14:26Z", "hours": 3.2111, "text": "was organizing my code and starting to add documentation, but got sidetracked and made this cool loading bar. Also im looking into adding ideas from https://charm.land/ but in python. (python)"}, {"post_id": 39587, "ts": "2026-08-02T17:42:08Z", "hours": 0.6153, "text": "21 demos completed, (defiantly not enough), added better char reading and the abilityto read words on the terminal, for better input options. (python)"}, {"post_id": 39189, "ts": "2026-08-01T23:51:39Z", "hours": 1.7586, "text": "finished up the clock then made a rhythm game. Planning on adding more features too it soon."}, {"post_id": 36716, "ts": "2026-07-28T23:05:45Z", "hours": 0.4114, "text": "clock works a lot better now, actually rotates properly, and hour is smoother."}, {"post_id": 36447, "ts": "2026-07-28T16:03:08Z", "hours": 1.3456, "text": "been a while since my last devlog, recently made a cool clock, based on realtime."}, {"post_id": 32116, "ts": "2026-07-21T01:50:24Z", "hours": 0.9439, "text": "got some plans, and started to go deep into the rabbit hole…"}, {"post_id": 29186, "ts": "2026-07-15T22:24:35Z", "hours": 1.0206, "text": "yay!, 40+ dependencies."}, {"post_id": 28972, "ts": "2026-07-15T16:20:22Z", "hours": 4.1825, "text": "created a screen mirror demo that i used to create a video for stardance socials: https://www.youtube.com/shorts/hIqH1Aea_eg and a basic windows spotlight img fetcher to have more imgs to showcase working in terminal, and started working on a quiz generator that could be used for better terminal install wizards, cool quizzes, or settings menus."}, {"post_id": 27706, "ts": "2026-07-13T14:31:29Z", "hours": 2.6381, "text": "added a video renderer, sadly text is pretty illegable on it, but it’s rendering them in the terminal so. Also has ability to pause videos as shown in the video with “ “, and even unpause, the video was downloaded with a another tool in this multitool im making. The video rendering uses sixel. (python)"}, {"post_id": 27235, "ts": "2026-07-12T16:53:20Z", "hours": 0.6825, "text": "got a .gif to load and run in the terminal (python), using sixtel."}, {"post_id": 27190, "ts": "2026-07-12T15:02:48Z", "hours": 1.2111, "text": "my dogo printed out with python, using sixtel."}, {"post_id": 26823, "ts": "2026-07-11T20:44:02Z", "hours": 0.9311, "text": "started to work on the dynamic window system more. But is verry much a wip, for the foreseeable future, but kinda works well enough to be functional for now."}, {"post_id": 24961, "ts": "2026-07-08T21:00:13Z", "hours": 0.6175, "text": "not much, just added loading text, so that when you load up the app, it doesn’t just freeze while figuring out what types your disks are. Also made it check for new disks every 10s."}, {"post_id": 24363, "ts": "2026-07-07T21:31:38Z", "hours": 4.3692, "text": "added this box, which grabs your memory stats, and disk stats, and is compatible with all themes."}, {"post_id": 23503, "ts": "2026-07-06T14:57:30Z", "hours": 1.9622, "text": "It’s starting to come together, and look really good, the top is a CPU usage visualizer, with a core by core view. Time in top center, and the bottom, is a cava-like audio visualizer (has it’s own demo too). Planning on adding coloring to the audio visualizer next, followed by more util functions. (python)"}, {"post_id": 22898, "ts": "2026-07-05T15:15:25Z", "hours": 2.0142, "text": "added the ability to switch themes with k, l and favorite themes with j, and also added a way to play music and download music through yt-dlp. (python)"}, {"post_id": 22197, "ts": "2026-07-04T15:30:43Z", "hours": 1.3022, "text": "here’s the nord theme in use, i “borrowed” some themes from btop’s repo, and have configured my current code to use the colors dynamically."}, {"post_id": 22158, "ts": "2026-07-04T14:07:07Z", "hours": 1.9108, "text": "Made a cool theme selector / preview, that allows you to view .theme files in the terminal, with arrow key navigation. left and right to switch the theme your viewing, up to favorite, and down to quit. I also made a custom debug theme for better contrast."}, {"post_id": 21571, "ts": "2026-07-03T16:27:40Z", "hours": 2.895, "text": "spent roughly 3 hours, making the CPU graph, might make it a gradient, or just move on to one of the other boxes. (python)"}, {"post_id": 13996, "ts": "2026-06-22T23:30:42Z", "hours": 2.9417, "text": "created the first square / section in my btop clone demo, gets info using winreg and psutil. (python)"}, {"post_id": 13455, "ts": "2026-06-22T01:10:12Z", "hours": 5.6906, "text": "I’ve been working on a custom box drawer, that works by giving it a list of corners and the length between them (sides) to draw a box with Unicode chars. Along with a couple of functions to get data from your pc, and a btop4win clone, (img) currently just have the outline and top bar, though."}, {"post_id": 12815, "ts": "2026-06-20T23:36:17Z", "hours": 1.0661, "text": "added another demo: were you can move your cursor with arrow keys, or just click where you want to type to start typing at that location, and if you middle click it will erase. It also uses the ‘esc’ key to exit. (python)"}, {"post_id": 12716, "ts": "2026-06-20T19:30:11Z", "hours": 0.9069, "text": "created a random based themed draw."}, {"post_id": 12674, "ts": "2026-06-20T18:21:21Z", "hours": 0.9928, "text": "added a canvas class with some drawing tools, like line, rect, circle."}, {"post_id": 12628, "ts": "2026-06-20T17:02:24Z", "hours": 1.2578, "text": "created a flipper zero cli."}, {"post_id": 12554, "ts": "2026-06-20T14:38:32Z", "hours": 2.5325, "text": "Finally, was able to add controller inputs, and handling for multiple inputs simultaniously, the img below shows me using both the left stick and right stick of a controller at the same time. Only using python, and the inputs module."}, {"post_id": 12141, "ts": "2026-06-19T20:48:24Z", "hours": 0.8978, "text": "added yet another demo, that allows you to place a constantly updating clock (as shown below) anywhere in your terminal window with python alone."}, {"post_id": 12081, "ts": "2026-06-19T18:33:35Z", "hours": 0.7272, "text": "made yet another demo, LC is left click, RC is right click, SU is scroll up, SD is scroll down, MC is middle click."}, {"post_id": 11998, "ts": "2026-06-19T16:03:02Z", "hours": 2.3969, "text": "just finished making another demo, how it works is you click on the x’s to increase your score and you can type “q” to quit and see stats. Had a lot of trouble making sure everything was cross terminal."}, {"post_id": 11512, "ts": "2026-06-18T20:04:49Z", "hours": 1.5133, "text": "added all core utility functions, plan on creating more demos, and useful functions next."}, {"post_id": 11386, "ts": "2026-06-18T17:03:50Z", "hours": 0.9169, "text": "created 2 demo func’s to show colors, and created a cursor class, that can control the cursor"}]...
|
Title: python Terminal multitool by @robopugo | St Title: python Terminal multitool by @robopugo | Stardance
Devlogs:
created 2 demo func’s to show colors, and created a cursor class, that can control the cursor
added all core utility functions, plan on creating more demos, and useful functions next.
just finished making another demo, how it works is you click on the x’s to increase your score and you can type “q” to quit and see stats. Had a lot of trouble making sure everything was cross terminal.
made yet another demo, LC is left click, RC is right click, SU is scroll up, SD is scroll down, MC is middle click.
added yet another demo, that allows you to place a constantly updating clock (as shown below) anywhere in your terminal window with python alone.
Finally, was able to add controller inputs, and handling for multiple inputs simultaniously, the img below shows me using both the left stick and right stick of a controller at the same time. Only using python, and the inputs module.
created a flipper zero cli.
added a canvas class with some drawing tools, like line, rect, circle.
created a random based themed draw.
added another demo: were you can move your cursor with arrow keys, or just click where you want to type to start typing at that location, and if you middle click it will erase. It also uses the ‘esc’ key to exit. (python)
I’ve been working on a custom box drawer, that works by giving it a list of corners and the length between them (sides) to draw a box with Unicode chars. Along with a couple of functions to get data from your pc, and a btop4win clone, (img) currently just have the outline and top bar, though.
created the first square / section in my btop clone demo, gets info using winreg and psutil. (python)
spent roughly 3 hours, making the CPU graph, might make it a gradient, or just move on to one of the other boxes. (python)
Made a cool theme selector / preview, that allows you to view .theme files in the terminal, with arrow key navigation. left and right to switch the theme your viewing, up to favorite, and down to quit. I also made a custom debug theme for better contrast.
here’s the nord theme in use, i “borrowed” some themes from btop’s repo, and have configured my current code to use the colors dynamically.
added the ability to switch themes with k, l and favorite themes with j, and also added a way to play music and download music through yt-dlp. (python)
It’s starting to come together, and look really good, the top is a CPU usage visualizer, with a core by core view. Time in top center, and the bottom, is a cava-like audio visualizer (has it’s own demo too). Planning on adding coloring to the audio visualizer next, followed by more util functions. (python)
added this box, which grabs your memory stats, and disk stats, and is compatible with all themes.
not much, just added loading text, so that when you load up the app, it doesn’t just freeze while figuring out what types your disks are. Also made it check for new disks every 10s.
started to work on the dynamic window system more. But is verry much a wip, for the foreseeable future, but kinda works well enough to be functional for now.
my dogo printed out with python, using sixtel.
got a .gif to load and run in the terminal (python), using sixtel.
added a video renderer, sadly text is pretty illegable on it, but it’s rendering them in the terminal so. Also has ability to pause videos as shown in the video with “ “, and even unpause, the video was downloaded with a another tool in this multitool im making. The video rendering uses sixel. (python)
created a screen mirror demo that i used to create a video for stardance socials: https://www.youtube.com/shorts/hIqH1Aea_eg and a basic windows spotlight img fetcher to have more imgs to showcase working in terminal, and started working on a quiz generator that could be used for better terminal install wizards, cool quizzes, or settings menus.
yay!, 40+ dependencies.
got some plans, and started to go deep into the rabbit hole…
been a while since my last devlog, recently made a cool clock, based on realtime.
clock works a lot better now, actually rotates properly, and hour is smoother.
finished up the clock then made a rhythm game. Planning on adding more features too it soon.
21 demos completed, (defiantly not enough), added better char reading and the abilityto read words on the terminal, for better input options. (python)
was organizing my code and starting to add documentation, but got sidetracked and made this cool loading bar. Also im looking into adding ideas from https://charm.land/ but in python. (python)
I think i speak computer now… reading terminal chars and converting to rgb, was easy….
donut i made that uses ANSI instead of Ascii to render. (python)
a terminal 4 color gradient that uses bilinear interpolation and ANSI. Also made a 1d gradient tool, and both can be used for data gradients. (python)
made a multi positional interpolated gradient in python, simply put, a gradient where you can have any amount of colors and you can pick their position.
I haven’t really documented this on star dance, but you can use ascii (or any color type or set of symbols, or even just data) in the gradients instead of rgb…
added a wrap func that is used to dynamically apply colors to strings, allowing you to easily print text that’s color is a gradient. (python)
started to mess with fonts and sadly a lot of fonts don’t support “\n”, but this one does, and i used wrap to apply the 4 color gradient to it, planning on working on adding the random text, and maybe another loading throbber of sorts. (python)
Hello, been a while, but I’m finally happy with it, so some context: python has these things called doc-strings which are basically special comments in a function that explain what the function does and how to use it, you can see this with the help() function. I wanted to make my own version, but stylized, and i succeeded, and mine is pretty dynamic. How it works: it uses a list of headers to make sections and then styles them based on indentation. (also shows color palate in bottom right). Planning on making some sort of menu to easily read these.
made the border a gradient, which honestly, just looks really good. Now going to work on the menu.
[this will be a longer devlog]. So what are these 2 things, and what do they have to do with stylized docs, glad you asked. After designing a stylized help func, I made a main menu / repl that shows you the names of all the functions and you can type the name to see its stylized doc card. The first img shows all of the names of the functions in my module currently, the second shows all of the helper funcs / commands in the repl. (not all are implemented, but most are). The main features I like are that it’s stateful with a back command, and the .run command which lets you run the example code right there. I uploaded a long form video to my YT channel if you want to see it in action: https://youtu.be/niP3qDd2KkY
small devlog, so one thing about my project is that it’s built to help others make tui’s, but not all projects are in python, so how did I learn to make this well I started here: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 , ANSI escape codes are just cli terminal coloring, add in some unicode and you got a cool stylized thingy. The img is an example of something I quickly built to showcase how much tui’s improve visuals, check it out here: https://codehs.com/sandbox/robopugo/gfojafowj/run . It’s still in python. Just wanted to share how I got introduced to Tui’s since I figured others might also want to find a way to get started.
it looks a lot better in the terminal but i made a big clock widget.
.mx was a fun new challenge after my little break from the tool, like .my it shows multiple docs, also supports the multi run, next feature to add is text warping. Hopefully I can get in 5hrs soon so i can get the limited stickers. :) (python)
added a favorites menu, and the ability to add functions to the favorites. Also added .ax and .ay . (python)
created this cool little form that you can fill out for a function to auto generate a docstring for it by default coppies it to clipboard but you can also have it auto write it in file. (i will admit i had to use some ai to figure out how to get it to write in file) (python)
made a readme veiwer similar to glow, that is fully customizable. supports h1-h6 p, lists, quotes, bold, italic, crossed, code inline, code blocks, and highlighted text. Main challenge was doing it without regex’s. (python)
I got themes working for the markdown renderer, but I got to lock in on everything else since Stardance is almost over. (video is bright.) (python)
added finishing touches to the markdown renderer. And went ahead and made another cool func that shows the dependencies of a function. Which was a pretty fun challenge. Also good news stardance is being extended to oct. 31. What team are you? (python)
A pretty easy feature that makes it significantly smoother and better. For example –A which doesn’t clear the screen, nor prints the help text. Overall pretty good QOL feature for the repl. (python)
added some file based commands (ls, pwd, cd.) to the repl, and created this cool colorized ascii img shower, as shown in img. Also finally reached 100hrs on this project, yipee!, some stats: over 100 functions, and over 4.5k lines (only 600 are empty), 57 imports, rougley 50% of functions have doc-strings and typed args, and over 3k word of documentation in the code. 19 classes. All in python....
|
1792637644.3863997
|
1793242444.3863997
|
|
29326
|
X-fight by @Eshan | Stardance
|
Eshan
|
0
|
100.3
|
0
|
[]
|
[{"post_id": 80872, "ts": "202 [{"post_id": 80872, "ts": "2026-10-19T03:45:33Z", "hours": 10.0886, "text": "Devlog 10 Hi, everybody! In my previous devlog, I mentioned that this would be my last devlog. But unfortunately, while integrating the features, I faced some unexpected issues related to match results, logic, and friendly match integration. 1. Working on the UI Most of my time went into completing the pending UI work. After that, I started fixing logical errors related to friendly matches and result uploading. 2. The Friendly Match Integration Problem Most of my existing match logic was designed for tournaments, which have an event ID. But friendly matches don’t belong to any tournament, so they don’t have an event ID. To solve this, I made the event ID optional in the match room function. def match_room ( request , match_room_id , event_id = None ): I also created separate URL patterns for tournament and friendly matches and used conditional logic to handle them differently. if not match . friendly_match_room : # Tournament logic pass else : # Friendly match logic pass 3. Fixing the Match Result Processing System My website uses JSON to pass match and tournament details. Friendly matches caused errors because they don’t have tournament information. So, I added conditional logic to set tournament-related values to None for friendly matches. if not match . friendly_match_room : tournament_name = match . tournament . name tournament_id = match . tournament . id winner_team = match . winner_team else : tournament_name = None tournament_id = None winner_team = None I then passed these variables into the JSON response. 4. Implementing the Loot Transfer Logic I also worked on the loot system for friendly matches. Loot refers to the coins players contribute to the match. For example, if four players contribute 100 coins each, the total loot pool becomes 400 coins, which the winner receives. I implemented this logic in the views so that loot is transferred only after a valid match result is determined. If a match is cancelled or ends without a valid result, no coins are transferred. So these are things I have done in this time period and so next will be last devlog I hope"}, {"post_id": 76159, "ts": "2026-10-02T15:17:51Z", "hours": 9.6864, "text": "Devlog-9 Hi everyone in my previous develog, I mentioned that this would probably be my last develog . However, after working on the project for several more hours, there are still a few UI improvements left to complete. So, this is approximately the final develog. The next update will definitely be the last one, as only a few UI changes remain. Almost all the major features and functionality are now completed. What I Worked On After the Previous Update In the previous update, I mentioned that I had integrated voice and video calling using ZEGOCLOUD. At that point, the calling functionality was working, but the UI was still based around the initial implementation. So, this time, I focused mainly on creating and integrating a custom calling UI of x-fight the black, red theme with ZEGOCLOUD. Major Update Revealing The Coin Transfer System One of the major new features I worked on is the coin system. The first part of this system is coin transfer between Game Mates. Users can now transfer their points to another game mate. The system includes the required forms, validation, calculations, through Django’s database transaction system. This ensures that the transfer is handled safely and consistently rather than simply changing the balance directly. ##Coin Transfer History I also implemented a Coin Transfer History feature. Users can now see their previous transfers and information such as: -Who they transferred points to -How many points were transferred -The transfer record -When the transfer happened This gives users a proper record of their coin activity. Tournament Entry Fees Another feature I integrated is tournament entry fees. Tournament creators can now choose whether a tournament has an entry fee or not. If a tournament has an entry fee, the required points are deducted when the player or team joins the tournament. The points are then handled as part of the tournament system, and the winner can receive the applicable reward mostly will be coins. Now after this feature only free tournaments issue is solved only as free competitions. Stats and Ranking System Finally, I have been working on connecting the points system with a new stats (ranking system). The idea is that players can use their coins to build their stats by buying it. These stats will then contribute to their position on the X-fight leaderboard. This gives the points system a purpose inside the X-fight ecosystem rather than making them simply numbers displayed on a profile. These are main feature I have worked in this time period"}, {"post_id": 71236, "ts": "2026-09-20T14:36:01Z", "hours": 9.8744, "text": "Devlog 8: Hey everyone! First of all, I’m sorry. In my last devlog, I said that it would be my final one before shipping the project. But unfortunately, I still had a few features left to complete, so I couldn’t finish everything as planned. So, most probably, the next devlog will be my last one, and after that, I’ll be shipping the project. Let me explain what happened. In my previous devlog, I mentioned that I was planning to integrate ZeeCloud and add voice and video calling to the chat application. My plan was to include voice calls, video calls, group voice calls, and group video calls. I spent almost 10 hours working on this integration. And honestly, I managed to get everything working. The calling features were functional, but I faced one major issue: I couldn’t properly integrate my own UI with the calling system. I tried different approaches and followed several tutorials, but I still couldn’t get the UI working the way I wanted. So, to be honest, I decided to delete all the code related to the calling features and start fresh. I felt that starting from scratch would be a better option than continuing with an approach that wasn’t working for me. That took up most of my time. With the remaining time, I worked on a few other features. The main feature I added was file sharing in the chat application. Until now, users couldn’t upload files in the chat. So, I integrated file uploading, and now users can send GIFs, photos, files, and other attachments. I also added an animation for the upload feature to make the experience a little smoother and more interactive. So, that’s pretty much what I’ve worked on this time. I couldn’t finish everything I had planned, but I still managed to make some progress. Hopefully, the next devlog will actually be the final one, and I’ll finally be shipping the project."}, {"post_id": 64835, "ts": "2026-09-09T15:01:36Z", "hours": 9.8286, "text": "Devlog - 7 Hi I thought this would be the last devlog of this project I thought this project will be finalized but unfortunately, it didn’t finish. so, in this time, I planned to do like there are some features which are incomplete like in notification, game scoreboard analyzing model, about page etc. so these are the changes I made. notification panel so, in this I have made in previous I just created it simply like a panel with message display but now i have added these features all clear button when a game mate request is sent if the action buttons are clicked then the notification will be cleared -when a game mate sends a chat message or through group chat then the notification will be displayed in this layout also, it has changes like it was placed in the navbar and when it is clicked a box will appear near to that were it display all the notification but due to responsive issue, I changed it into a centralized popup screen and a close button to close that. layout changes Actually, I have some design works to do so I have done that. some page mainly forms lie team register tournament register, so I have applied themes of the whole site so next I did was not in my plan list, but when I am testing it I notice a drawback like when a user creates a team, they cannot modify it, so I have added that feature, so these are that features overview it just like in normal dashboard displaying No. of tournaments, Mathes and members displaying them Team captain this idea sparkled when I was playing football game so in this they who can schedule meetings give directions through team chat room Election system this was basically an election for team captain everyone has the right to vote there and who has more vote they will be the team captain instead of manual update . meeting room this a place where the team captian can schedule team meeting and a conference window will be opened they can do a face-to-face video call .so here I need to tell you something here Zee cloud helped like instead of writing a huge code of webrtc,django channel it helps to do integrated video conference through Api and it is very useful when we are starting Chatroom a place for team members can chat without creating a chatgroup next I added some more features in Matchroom these are the features in Matchroom ##more game models I have added like game model option for other it is a general for all games Ready or Not Ready this was the old same feature, but I have integrated the Django channels and web sockets count down here if every player clicks the ready button the 12 sec countdowns will be starting and after that they cannot press the no ready button and the match duration will be done then they have to end it and upload the photo by the persons from two teams and then we will cross check it and it is matched then the points will be credited otherwise it will be rejected and the match may reconduct it will be based on the tournament admins like if they want to conduct then they can otherwise the match will be abandoned these are the things I have done I think next will be the last devlog"}, {"post_id": 56747, "ts": "2026-08-28T17:02:28Z", "hours": 9.4822, "text": "Develog 6 Hi everybody it’s been a while. I was on break for some days due to my exams. so up to this time I was mainly focused on the design of the website here in many parts I have completely changed the layout in some places, and I came to a final color theme black red white these are the main color theme up to this time in dashboard the sidebar was just for a show it doesn’t work but now I made it functional and these are the options dashboard – it just shows a summary like the rank on the leaderboard, total tournaments joined, etc. tournaments matches game mates – it displays all the game mates and options to block, remove chats – display all the chats like to chat with the game mates and group chats logout in chat there is like i implemented a minimal clean look and it also has a sidebar whith these options display all chats search bar filter button – All, Game mates, Group Chats in right side I has like normal like chat and when a group invite is sent then in a different style in sender the request will be sent these are major layout changes in all other I just charge the color theme."}, {"post_id": 46358, "ts": "2026-08-13T15:07:00Z", "hours": 8.5808, "text": "Develog -5 hi everybody i have now completed the chat feature in my website. in this there are three types like group chat, privet chat and announcement chat. Group chat in this group chat it’s like normal chat like here you can make groups with the game mates only I have done making this chat system here the flow is like in the the inter face there is a button called create chatgroup if that we click then it will ask for the name, we should enter the name then the group will be created and after that it will take to the chat interface in that we have button called info were all the group members are listed and who re the admins and the group name there we have button called invite when that clicked then ta popup will be coming and all the game mates will be displayed along with send button when the send button is clicked then a special type message will send I call that as a group invite request and if they press the join then they will be added as a member. the group admin has the access to delete or make a member as admin o remove from admin position and users have option to let the group Privet Chat in this privet chat if like to chat with the game mates. the workflow is like there will be like in the chat interface all the game mates are listed if we click on them then the chatting interface will be opened where we can chat as normal and there is a button indicate online or not Announcement Chat here it like all the tournament owners can create a chat room to announce the news of their tournaments it will be admin message only chat players cannot send any messages if any doubt is there then a chatroom will also open there, they can ask doubt. chat interface the chat interface like I has designed like in dashboard there will be a button called enter the community like all the chat will be listed only one there. and it has button call return to base camp if that press then it will be returned to the dashboard. while making this like this is the first time I am working with WebSocket’s and Django channels I got many errors so that time I have mainly used the stack overflow and after I got the base of Django channels the first project to try that is this project the uploaded photo is the chat interface and I am not that good Ui design building I find a similar theme in internet I don’t know this is good anyone has suggestion please put in comments"}, {"post_id": 42666, "ts": "2026-08-07T14:45:52Z", "hours": 11.1, "text": "Develog-4 Up to this time as I said in previous develog that planning to integrate a XP point addition no I have done that. if a player one a game that player now will get a 50XP point. but I am planning like for some team game to split the total xp-points to every team member. After that I moved to make the chatting system here up to this time I have done to create a public chatroom were everyone can join and chat but after the creation of this public chat I will be creating a two-type chatroom one is 1v1 chat and group chat and I am doing this with WebSocket’s and Django channels and I have created a friend request method also were every player dashboard has a notification bar and every players can send a friend request to every other players and instead of this normal name called as friend request I named it as game-mate request and every players can chat with their game mate and they can create groups with their game mate and they can reject the request also and if they try to send request multiple times it won’t work it will directly redirect to dashboard and the player search screen will display with the z index in dashboard and I have temporary added this design tike that chat interface al to make the functionalities"}, {"post_id": 39320, "ts": "2026-08-02T06:55:42Z", "hours": 10.4797, "text": "Develog - 3 This week I have mainly worked on creating Ai for the updating scoreboard with just a screen shot of the game scoreboard and up to this time I have added only for e-football and I am planning to add specific for some games and one for general. in this journey I tried mainly to create the AI myself so I researched how to do then I came to the idea of like it extract text from the image and I have used these three text excretion library called Easyocr, Pyteseract and Paddleocr but this I tried but here the main problem I faced is that they just extract the text but some time that will not able to I identify some small text and from that I cannot set who is the winner then I came to an idea to create an LLM using Pytorch with these neural network but when I started to do I faced a problem that my laptop is a office laptop so I cannot make such kind of LLM by my own because this lap cannot handle it. so I decided to use the google ai vision tool so now know from the beginning but I just want to create my own but due to this problems I use google ai vision it good by using a specific model I got 500 request per day(RPD) and now I have integrated that withe frontend like when they upload the scoreboard it will say analyzing the match after the Gemini response and save data in Json file in a format with some extra details like which match came the result came then only it will redirect to the main page and now I need to add the scoreboard, I am planning to add XP-points and some special extraction of score for some specific game"}, {"post_id": 30497, "ts": "2026-07-18T03:47:21Z", "hours": 9.5078, "text": "Devlog #2 This week, I worked mainly on improving the tournament flow and adding several new features to make the experience smoother for players. The first thing I completed was the User Dashboard and the Tournament Settings Dashboard. I also redesigned their UI to make them cleaner and easier to use. I then updated the tournament listing page so that it only shows tournaments that the user has not joined yet. This keeps the page organized and avoids showing tournaments that are already in the player’s list. On the User Dashboard, players can now see every tournament they have joined. Clicking on any of them opens the Tournament Dashboard, where they can view all the matches scheduled for that tournament. In the Tournament Dashboard, there is a Scheduled Match button that takes users to the Match Creation page. The match list has also been filtered so that only upcoming and currently active matches are displayed. Each match has an Enter button. When players enter the Match Room, they can see all the members of both teams along with their current status. A Ready button is available for every player. Once a player clicks it, their status changes from Waiting to Ready, allowing everyone to know who is prepared for the match.When every player is marked as Ready, a 15-second countdown starts automatically. During the first few seconds, players can still change their status back to Not Ready if needed. However, once the countdown reaches 7 seconds, the Ready status is locked, preventing anyone from switching back. This helps avoid last-second cancellations and keeps matches starting on time. These changes make the tournament system more organized and improve the overall experience before a match begins."}, {"post_id": 25452, "ts": "2026-07-09T18:44:38Z", "hours": 11.6717, "text": "i am building a website for gamers were they can create or schedule matches and win points and they can conduct tournaments and were they can set the price and sent to the winners it has a leaderboard and the top 3 will be displayed on homepage and they can even talk each other via chat message up to now i have made tournament registration like ere the users can create a tournament and enter the details such as name ,game, name whether is a teams or solo match tournament and the points and i have also created the team creation were every users can create a team by selecting their team mates ani have most of the time for creating this Ui like searching for a good theme and i have added login and registration were users can Create account and they can upload profile picture"}]...
|
Title: X-fight by @Eshan | Stardance
Devlogs:
i a Title: X-fight by @Eshan | Stardance
Devlogs:
i am building a website for gamers were they can create or schedule matches and win points and they can conduct tournaments and were they can set the price and sent to the winners it has a leaderboard and the top 3 will be displayed on homepage and they can even talk each other via chat message up to now i have made tournament registration like ere the users can create a tournament and enter the details such as name ,game, name whether is a teams or solo match tournament and the points and i have also created the team creation were every users can create a team by selecting their team mates ani have most of the time for creating this Ui like searching for a good theme and i have added login and registration were users can Create account and they can upload profile picture
Devlog #2 This week, I worked mainly on improving the tournament flow and adding several new features to make the experience smoother for players. The first thing I completed was the User Dashboard and the Tournament Settings Dashboard. I also redesigned their UI to make them cleaner and easier to use. I then updated the tournament listing page so that it only shows tournaments that the user has not joined yet. This keeps the page organized and avoids showing tournaments that are already in the player’s list. On the User Dashboard, players can now see every tournament they have joined. Clicking on any of them opens the Tournament Dashboard, where they can view all the matches scheduled for that tournament. In the Tournament Dashboard, there is a Scheduled Match button that takes users to the Match Creation page. The match list has also been filtered so that only upcoming and currently active matches are displayed. Each match has an Enter button. When players enter the Match Room, they can see all the members of both teams along with their current status. A Ready button is available for every player. Once a player clicks it, their status changes from Waiting to Ready, allowing everyone to know who is prepared for the match.When every player is marked as Ready, a 15-second countdown starts automatically. During the first few seconds, players can still change their status back to Not Ready if needed. However, once the countdown reaches 7 seconds, the Ready status is locked, preventing anyone from switching back. This helps avoid last-second cancellations and keeps matches starting on time. These changes make the tournament system more organized and improve the overall experience before a match begins.
Develog - 3 This week I have mainly worked on creating Ai for the updating scoreboard with just a screen shot of the game scoreboard and up to this time I have added only for e-football and I am planning to add specific for some games and one for general. in this journey I tried mainly to create the AI myself so I researched how to do then I came to the idea of like it extract text from the image and I have used these three text excretion library called Easyocr, Pyteseract and Paddleocr but this I tried but here the main problem I faced is that they just extract the text but some time that will not able to I identify some small text and from that I cannot set who is the winner then I came to an idea to create an LLM using Pytorch with these neural network but when I started to do I faced a problem that my laptop is a office laptop so I cannot make such kind of LLM by my own because this lap cannot handle it. so I decided to use the google ai vision tool so now know from the beginning but I just want to create my own but due to this problems I use google ai vision it good by using a specific model I got 500 request per day(RPD) and now I have integrated that withe frontend like when they upload the scoreboard it will say analyzing the match after the Gemini response and save data in Json file in a format with some extra details like which match came the result came then only it will redirect to the main page and now I need to add the scoreboard, I am planning to add XP-points and some special extraction of score for some specific game
Develog-4 Up to this time as I said in previous develog that planning to integrate a XP point addition no I have done that. if a player one a game that player now will get a 50XP point. but I am planning like for some team game to split the total xp-points to every team member. After that I moved to make the chatting system here up to this time I have done to create a public chatroom were everyone can join and chat but after the creation of this public chat I will be creating a two-type chatroom one is 1v1 chat and group chat and I am doing this with WebSocket’s and Django channels and I have created a friend request method also were every player dashboard has a notification bar and every players can send a friend request to every other players and instead of this normal name called as friend request I named it as game-mate request and every players can chat with their game mate and they can create groups with their game mate and they can reject the request also and if they try to send request multiple times it won’t work it will directly redirect to dashboard and the player search screen will display with the z index in dashboard and I have temporary added this design tike that chat interface al to make the functionalities
Develog -5 hi everybody i have now completed the chat feature in my website. in this there are three types like group chat, privet chat and announcement chat. Group chat in this group chat it’s like normal chat like here you can make groups with the game mates only I have done making this chat system here the flow is like in the the inter face there is a button called create chatgroup if that we click then it will ask for the name, we should enter the name then the group will be created and after that it will take to the chat interface in that we have button called info were all the group members are listed and who re the admins and the group name there we have button called invite when that clicked then ta popup will be coming and all the game mates will be displayed along with send button when the send button is clicked then a special type message will send I call that as a group invite request and if they press the join then they will be added as a member. the group admin has the access to delete or make a member as admin o remove from admin position and users have option to let the group Privet Chat in this privet chat if like to chat with the game mates. the workflow is like there will be like in the chat interface all the game mates are listed if we click on them then the chatting interface will be opened where we can chat as normal and there is a button indicate online or not Announcement Chat here it like all the tournament owners can create a chat room to announce the news of their tournaments it will be admin message only chat players cannot send any messages if any doubt is there then a chatroom will also open there, they can ask doubt. chat interface the chat interface like I has designed like in dashboard there will be a button called enter the community like all the chat will be listed only one there. and it has button call return to base camp if that press then it will be returned to the dashboard. while making this like this is the first time I am working with WebSocket’s and Django channels I got many errors so that time I have mainly used the stack overflow and after I got the base of Django channels the first project to try that is this project the uploaded photo is the chat interface and I am not that good Ui design building I find a similar theme in internet I don’t know this is good anyone has suggestion please put in comments
Develog 6 Hi everybody it’s been a while. I was on break for some days due to my exams. so up to this time I was mainly focused on the design of the website here in many parts I have completely changed the layout in some places, and I came to a final color theme black red white these are the main color theme up to this time in dashboard the sidebar was just for a show it doesn’t work but now I made it functional and these are the options dashboard – it just shows a summary like the rank on the leaderboard, total tournaments joined, etc. tournaments matches game mates – it displays all the game mates and options to block, remove chats – display all the chats like to chat with the game mates and group chats logout in chat there is like i implemented a minimal clean look and it also has a sidebar whith these options display all chats search bar filter button – All, Game mates, Group Chats in right side I has like normal like chat and when a group invite is sent then in a different style in sender the request will be sent these are major layout changes in all other I just charge the color theme.
Devlog - 7 Hi I thought this would be the last devlog of this project I thought this project will be finalized but unfortunately, it didn’t finish. so, in this time, I planned to do like there are some features which are incomplete like in notification, game scoreboard analyzing model, about page etc. so these are the changes I made. notification panel so, in this I have made in previous I just created it simply like a panel with message display but now i have added these features all clear button when a game mate request is sent if the action buttons are clicked then the notification will be cleared -when a game mate sends a chat message or through group chat then the notification will be displayed in this layout also, it has changes like it was placed in the navbar and when it is clicked a box will appear near to that were it display all the notification but due to responsive issue, I changed it into a centralized popup screen and a close button to close that. layout changes Actually, I have some design works to do so I have done that. some page mainly forms lie team register tournament register, so I have applied themes of the whole site so next I did was not in my plan list, but when I am testing it I notice a drawback like when a user creates a team, they cannot modify it, so I have added that feature, so these are that features overview it just like in normal dashboard displaying No. of tournaments, Mathes and members displaying them Team captain this idea sparkled when I was playing football game so in this they who can schedule meetings give directions through team chat room Election system this was basically an election for team captain everyone has the right to vote there and who has more vote they will be the team captain instead of manual update . meeting room this a place where the team captian can schedule team meeting and a conference window will be opened they can do a face-to-face video call .so here I need to tell you something here Zee cloud helped like instead of writing a huge code of webrtc,django channel it helps to do integrated video conference through Api and it is very useful when we are starting Chatroom a place for team members can chat without creating a chatgroup next I added some more features in Matchroom these are the features in Matchroom ##more game models I have added like game model option for other it is a general for all games Ready or Not Ready this was the old same feature, but I have integrated the Django channels and web sockets count down here if every player clicks the ready button the 12 sec countdowns will be starting and after that they cannot press the no ready button and the match duration will be done then they have to end it and upload the photo by the persons from two teams and then we will cross check it and it is matched then the points will be credited otherwise it will be rejected and the match may reconduct it will be based on the tournament admins like if they want to conduct then they can otherwise the match will be abandoned these are the things I have done I think next will be the last devlog
Devlog 8: Hey everyone! First of all, I’m sorry. In my last devlog, I said that it would be my final one before shipping the project. But unfortunately, I still had a few features left to complete, so I couldn’t finish everything as planned. So, most probably, the next devlog will be my last one, and after that, I’ll be shipping the project. Let me explain what happened. In my previous devlog, I mentioned that I was planning to integrate ZeeCloud and add voice and video calling to the chat application. My plan was to include voice calls, video calls, group voice calls, and group video calls. I spent almost 10 hours working on this integration. And honestly, I managed to get everything working. The calling features were functional, but I faced one major issue: I couldn’t properly integrate my own UI with the calling system. I tried different approaches and followed several tutorials, but I still couldn’t get the UI working the way I wanted. So, to be honest, I decided to delete all the code related to the calling features and start fresh. I felt that starting from scratch would be a better option than continuing with an approach that wasn’t working for me. That took up most of my time. With the remaining time, I worked on a few other features. The main feature I added was file sharing in the chat application. Until now, users couldn’t upload files in the chat. So, I integrated file uploading, and now users can send GIFs, photos, files, and other attachments. I also added an animation for the upload feature to make the experience a little smoother and more interactive. So, that’s pretty much what I’ve worked on this time. I couldn’t finish everything I had planned, but I still managed to make some progress. Hopefully, the next devlog will actually be the final one, and I’ll finally be shipping the project.
Devlog-9 Hi everyone in my previous develog, I mentioned that this would probably be my last develog . However, after working on the project for several more hours, there are still a few UI improvements left to complete. So, this is approximately the final develog. The next update will definitely be the last one, as only a few UI changes remain. Almost all the major features and functionality are now completed. What I Worked On After the Previous Update In the previous update, I mentioned that I had integrated voice and video calling using ZEGOCLOUD. At that point, the calling functionality was working, but the UI was still based around the initial implementation. So, this time, I focused mainly on creating and integrating a custom calling UI of x-fight the black, red theme with ZEGOCLOUD. Major Update Revealing The Coin Transfer System One of the major new features I worked on is the coin system. The first part of this system is coin transfer between Game Mates. Users can now transfer their points to another game mate. The system includes the required forms, validation, calculations, through Django’s database transaction system. This ensures that the transfer is handled safely and consistently rather than simply changing the balance directly. ##Coin Transfer History I also implemented a Coin Transfer History feature. Users can now see their previous transfers and information such as: -Who they transferred points to -How many points were transferred -The transfer record -When the transfer happened This gives users a proper record of their coin activity. Tournament Entry Fees Another feature I integrated is tournament entry fees. Tournament creators can now choose whether a tournament has an entry fee or not. If a tournament has an entry fee, the required points are deducted when the player or team joins the tournament. The points are then handled as part of the tournament system, and the winner can receive the applicable reward mostly will be coins. Now after this feature only free tournaments issue is solved only as free competitions. Stats and Ranking System Finally, I have been working on connecting the points system with a new stats (ranking system). The idea is that players can use their coins to build their stats by buying it. These stats will then contribute to their position on the X-fight leaderboard. This gives the points system a purpose inside the X-fight ecosystem rather than making them simply numbers displayed on a profile. These are main feature I have worked in this time period
Devlog 10 Hi, everybody! In my previous devlog, I mentioned that this would be my last devlog. But unfortunately, while integrating the features, I faced some unexpected issues related to match results, logic, and friendly match integration. 1. Working on the UI Most of my time went into completing the pending UI work. After that, I started fixing logical errors related to friendly matches and result uploading. 2. The Friendly Match Integration Problem Most of my existing match logic was designed for tournaments, which have an event ID. But friendly matches don’t belong to any tournament, so they don’t have an event ID. To solve this, I made the event ID optional in the match room function. def match_room ( request , match_room_id , event_id = None ): I also created separate URL patterns for tournament and friendly matches and used conditional logic to handle them differently. if not match . friendly_match_room : # Tournament logic pass else : # Friendly match logic pass 3. Fixing the Match Result Processing System My website uses JSON to pass match and tournament details. Friendly matches caused errors because they don’t have tournament information. So, I added conditional logic to set tournament-related values to None for friendly matches. if not match . friendly_match_room : tournament_name = match . tournament . name tournament_id = match . tournament . id winner_team = match . winner_team else : tournament_name = None tournament_id = None winner_team = None I then passed these variables into the JSON response. 4. Implementing the Loot Transfer Logic I also worked on the loot system for friendly matches. Loot refers to the coins players contribute to the match. For example, if four players contribute 100 coins each, the total loot pool becomes 400 coins, which the winner receives. I implemented this logic in the views so that loot is transferred only after a valid match result is determined. If a match is cancelled or ends without a valid result, no coins are transferred. So these are things I have done in this time period and so next will be last devlog I hope...
|
1792511259.2017822
|
1793116059.2017822
|
|
9377
|
Yet another music app by @MHanak | Stardance
|
MHanak
|
1
|
100.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-09T15:17:13Z", "hours": 100.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Well, the do-it-all * music app is done * * . It took longer than I expected, and i wasn’t able to squeeze in all of the features i wanted to add, but i’m still happy with the result. *okay, maybe not “all”, but quite a lot. **except for a bunch of features i’m hoping to add down the line.", "repo": "https://github.com/MHanak1/Yama", "demo": "https://github.com/MHanak1/Yama/releases/latest"}]...
|
[{"post_id": 59203, "ts": "202 [{"post_id": 59203, "ts": "2026-08-31T21:12:58Z", "hours": 3.9753, "text": "Soo, I did some more work, mostly on the desktop polishing front, anything from keyboard controls, to better Windows support and the ability to change the app theme through a file (for all of you spicers out there). Other than that, the one feature i’ve added is the ability to edit playlists, which has been missing for quite a while now."}, {"post_id": 50805, "ts": "2026-08-20T06:40:36Z", "hours": 6.9714, "text": "You wake up. You don’t remember a lot from last night; in fact, you aren’t really sure if you remember anything from the previous day. Regardless, you are filled with a overwhelming need to listen to something. Remembering only the title, you search for it, and in an instant your room if filled with soothing music, exactly the song you wanted. Listening to it slowly reminds you what happened on the previous day. Hey, i’ve gotten pretty good at writing these, anyway, I’ve added a global search function to the app, which searches through tracks, albums, artists, etc. all at once. I also did a * ton * of other small fixes and improvements. If you want to test out the app, You can get it from https://github.com/MHanak1/Yama/releases/latest"}, {"post_id": 46159, "ts": "2026-08-13T05:38:16Z", "hours": 2.9431, "text": "No fancy speak again, it’s too early for that and I haven’t finished my coffe yet, but i finally made a homescreen to the app! I have made it configurable, so you can select which shelves to include on it, and i’ll be adding more configuration options later (i need some ideas here). Other than that i worked on some minor bug fixes, mostly layout based like mismatched padding, and finally set up a github CI to package the app, so you can now get it from the github’s releases page (i should probably test the windows build shouldn’t i?)"}, {"post_id": 40611, "ts": "2026-08-04T08:34:13Z", "hours": 6.1036, "text": "Sooo. a bunch of time went into trying to implement proper playback caching, and i am glad to announce it was an absolute disaster. That aside, I made a pretty README! frankly, the best one I’ve made yet, full of screenshots and the such. I’ll probably be slowly trying to bundle the app for all platforms, and will be publishing the app fairly soon"}, {"post_id": 31750, "ts": "2026-07-20T12:04:32Z", "hours": 6.4519, "text": "Well, again no groundbreaking features, but i’ve made the app’s design more in line with material3 expressive, so the player’s appearance has been improved. I have also iproved the login screen’s appearance, added listens scrobbling to ListebBrainz, and solved some issues with the playback status not being reported properly to the server."}, {"post_id": 21685, "ts": "2026-07-03T19:29:54Z", "hours": 10.1486, "text": "You stop the music. Blissful silence surrounds you as you delve into the sea of tranquillity. You float in the endless void for minutes, hours; the passage of time becomes meaningless in a space devoid of change. Suddenly, you hear a faint sound. You feel compelled to drift toward it. The chirping gets louder and louder; the periodic pings become almost hypnotising. Then you see it - the yellow submarine, faintly lit by its onboard lights. On its hull you can see its name - Subsonic. Added Subsonic support. Other than that, there were a lot of changes under the hood to organise the code and how the state flows throughout the app. I have also re-designed the source switcher, which you can see on the screenshot"}, {"post_id": 11122, "ts": "2026-06-18T06:01:13Z", "hours": 9.6864, "text": "Before, you could only listen to music on earth, where you can mingle with the with the ubiquitous ‘internet’. But now, you can go higher. You can listen to music on the moon! That’s right Kennedy, you can listen to music on the moon! i added a system for downloading music from jellyfin (and others). This way when you go offline you can listen to songs you downloaded. Additionally, the app can cache songs which were listened to recently, and it will keep a certain amount of the files for local playback as well"}, {"post_id": 8942, "ts": "2026-06-14T21:15:11Z", "hours": 12.1736, "text": "Okay this time no fancy speak, i am way overdue a devlog, but i haven’t worked on a single feature which would have justified a devlog devoted solely to it, so here’s a roundup of things i implemented over the past couple days: Improved remote jellyfin playback handling, < rant > Hey, would you believe it that Jellyfin’s “Play on” is a piece of crap when it comes to music? Even the official client’s implementation is really broken when using it for music. there’s no mechanism through which i could measure the delay with which the music is playing, so you can expect a couple second delay between the lyrics on your phone and the music playing on the TV. i have to make educated guesses about the TV’s playback state. Also, there’s no websocket command to rearrange the playback queue, you can only push a new queue, but i’ve gotten around that. Also i had a ton of desync issues even after i spent more time on this than i reasonably should have . Oh, and did i mention there is no documentation whatsoever? you gotta figure out what you have to do by looking at the messages and the SDK < /rant > Did some tweaks to the UI colors (now it’s prettier ) You can favorite/unfavorite albums now There’s a new, prettier and more functional queue manager (visible in the screenshot) Tried (and failed) to make the TV focus issues go away Added support for local audio files along with metadata scanning (no remote fetching though), so you can use this app as an mp3 player even if you don’t have a media server Made the album, artist, etc. detail pages prettier . To the library, added the tracks page, in which you can view them in order of most played, date added, random, etc. Added the ability to play/shuffle entire albums, artists, etc, and multiple of them at once. and more"}, {"post_id": 6789, "ts": "2026-06-11T11:31:51Z", "hours": 1.1922, "text": "What is a book without a cover? well, still a book but it looks kinda bad on the bookshelf. Nonetheless, i have meticulously pondered the appearance of the icon, drawing my inspiration from mathematics, which some describe as the most beautiful of sciences. I made the app icon, and it’s basically the graph of sin(x)/x"}, {"post_id": 6758, "ts": "2026-06-11T09:46:02Z", "hours": 0.5372, "text": "Oh also i found a bug where i could play movies through the app XD this really shouldn’t be its own devlog, but i found that funny enough that i needed to share this. This isn’t the movie’s soundtrack, the entire movie’s audio is playing through the app"}, {"post_id": 6731, "ts": "2026-06-11T08:28:57Z", "hours": 11.3311, "text": "You behold the screen, your window into the melody. but what you see this time is not the decorations imprinted into the tracks, oh no, what you see is the words of the song itself, dancing happily to the rhythm. You sing with them, as you are just as happy. added the lyrics screen Next, you reach down towards your pocket. You pull out your phone, and through it you open the app. To your amazement, a command travels through waves of ether, casting a different melody upon your television. added support for Jellyfin’s “Play on” feature, which allows for remote playback Okay this time i probably should have made a devlog earlier, and i guess you’re getting a bit of a bigger devlog. Other than the above two i did some more changes: made it so the UI is recolored based on the album covers did some cover prefetching so images should load on-screen less often made the player UI prettier, also if the device is not interacted with for a bit, it will hide away the player controls which i think looks pretty neat and more™"}, {"post_id": 5023, "ts": "2026-06-08T17:52:47Z", "hours": 3.3983, "text": "After many hours, i find the perfect song, i press it, and in this moment the app floods my ears with a beautiful symphony. The sound is almost soothing, yet reassuring. The music app has ultimately gained the ability to fulfill its paramount function, to fill its users ears with melody. nah who am i kidding i vibecoded the hell out of that, still took me a while to get the UI to be decent, also hey, look! it works on the tv too!"}, {"post_id": 4839, "ts": "2026-06-08T11:18:36Z", "hours": 3.8478, "text": "What is a music app that does not allow one to gaze upon their songs, beautifully laid in a tidy, yet not overly strict list? Well, still a music app, as one does not look at music, but rather hears it. Alas, the graphical layer still felt to me to have equal importance. What you behold in this attached screenshot is a page meant to express, in a visually appealing manner, the songs that make up a music album. Yes i will write all my devlogs like that and you can’t stop me"}, {"post_id": 3543, "ts": "2026-06-06T15:04:19Z", "hours": 20.9111, "text": "So stardance is apparently a thing… well, I’ve been making a music app for jellyfin (and others) over the last bit, so i decided i’d track it with stardance! No detailed devlogs for the 20 hours because i wasn’t planning on doing stardance, but from now on i promise i will be a good cookie and post detailed devlogs from now on But what i did up to this point, is setting up a compose app, fiddling with the jellyfin sdk (this gives me the server discovery feature, but means that for now it will be incompatible with ios), did some layouting, sweet-sweet blurring with haze for that liquid glass aesthetic, and then much, much more layouting but thanks to that lot-of-layouting, the app will be usable across mobile, desktop and even your TV!"}]...
|
Title: Yet another music app by @MHanak | Stardanc Title: Yet another music app by @MHanak | Stardance
Devlogs:
So stardance is apparently a thing… well, I’ve been making a music app for jellyfin (and others) over the last bit, so i decided i’d track it with stardance! No detailed devlogs for the 20 hours because i wasn’t planning on doing stardance, but from now on i promise i will be a good cookie and post detailed devlogs from now on But what i did up to this point, is setting up a compose app, fiddling with the jellyfin sdk (this gives me the server discovery feature, but means that for now it will be incompatible with ios), did some layouting, sweet-sweet blurring with haze for that liquid glass aesthetic, and then much, much more layouting but thanks to that lot-of-layouting, the app will be usable across mobile, desktop and even your TV!
What is a music app that does not allow one to gaze upon their songs, beautifully laid in a tidy, yet not overly strict list? Well, still a music app, as one does not look at music, but rather hears it. Alas, the graphical layer still felt to me to have equal importance. What you behold in this attached screenshot is a page meant to express, in a visually appealing manner, the songs that make up a music album. Yes i will write all my devlogs like that and you can’t stop me
After many hours, i find the perfect song, i press it, and in this moment the app floods my ears with a beautiful symphony. The sound is almost soothing, yet reassuring. The music app has ultimately gained the ability to fulfill its paramount function, to fill its users ears with melody. nah who am i kidding i vibecoded the hell out of that, still took me a while to get the UI to be decent, also hey, look! it works on the tv too!
You behold the screen, your window into the melody. but what you see this time is not the decorations imprinted into the tracks, oh no, what you see is the words of the song itself, dancing happily to the rhythm. You sing with them, as you are just as happy. added the lyrics screen Next, you reach down towards your pocket. You pull out your phone, and through it you open the app. To your amazement, a command travels through waves of ether, casting a different melody upon your television. added support for Jellyfin’s “Play on” feature, which allows for remote playback Okay this time i probably should have made a devlog earlier, and i guess you’re getting a bit of a bigger devlog. Other than the above two i did some more changes: made it so the UI is recolored based on the album covers did some cover prefetching so images should load on-screen less often made the player UI prettier, also if the device is not interacted with for a bit, it will hide away the player controls which i think looks pretty neat and more™
Oh also i found a bug where i could play movies through the app XD this really shouldn’t be its own devlog, but i found that funny enough that i needed to share this. This isn’t the movie’s soundtrack, the entire movie’s audio is playing through the app
What is a book without a cover? well, still a book but it looks kinda bad on the bookshelf. Nonetheless, i have meticulously pondered the appearance of the icon, drawing my inspiration from mathematics, which some describe as the most beautiful of sciences. I made the app icon, and it’s basically the graph of sin(x)/x
Okay this time no fancy speak, i am way overdue a devlog, but i haven’t worked on a single feature which would have justified a devlog devoted solely to it, so here’s a roundup of things i implemented over the past couple days: Improved remote jellyfin playback handling, < rant > Hey, would you believe it that Jellyfin’s “Play on” is a piece of crap when it comes to music? Even the official client’s implementation is really broken when using it for music. there’s no mechanism through which i could measure the delay with which the music is playing, so you can expect a couple second delay between the lyrics on your phone and the music playing on the TV. i have to make educated guesses about the TV’s playback state. Also, there’s no websocket command to rearrange the playback queue, you can only push a new queue, but i’ve gotten around that. Also i had a ton of desync issues even after i spent more time on this than i reasonably should have . Oh, and did i mention there is no documentation whatsoever? you gotta figure out what you have to do by looking at the messages and the SDK < /rant > Did some tweaks to the UI colors (now it’s prettier ) You can favorite/unfavorite albums now There’s a new, prettier and more functional queue manager (visible in the screenshot) Tried (and failed) to make the TV focus issues go away Added support for local audio files along with metadata scanning (no remote fetching though), so you can use this app as an mp3 player even if you don’t have a media server Made the album, artist, etc. detail pages prettier . To the library, added the tracks page, in which you can view them in order of most played, date added, random, etc. Added the ability to play/shuffle entire albums, artists, etc, and multiple of them at once. and more
Before, you could only listen to music on earth, where you can mingle with the with the ubiquitous ‘internet’. But now, you can go higher. You can listen to music on the moon! That’s right Kennedy, you can listen to music on the moon! i added a system for downloading music from jellyfin (and others). This way when you go offline you can listen to songs you downloaded. Additionally, the app can cache songs which were listened to recently, and it will keep a certain amount of the files for local playback as well
You stop the music. Blissful silence surrounds you as you delve into the sea of tranquillity. You float in the endless void for minutes, hours; the passage of time becomes meaningless in a space devoid of change. Suddenly, you hear a faint sound. You feel compelled to drift toward it. The chirping gets louder and louder; the periodic pings become almost hypnotising. Then you see it - the yellow submarine, faintly lit by its onboard lights. On its hull you can see its name - Subsonic. Added Subsonic support. Other than that, there were a lot of changes under the hood to organise the code and how the state flows throughout the app. I have also re-designed the source switcher, which you can see on the screenshot
Well, again no groundbreaking features, but i’ve made the app’s design more in line with material3 expressive, so the player’s appearance has been improved. I have also iproved the login screen’s appearance, added listens scrobbling to ListebBrainz, and solved some issues with the playback status not being reported properly to the server.
Sooo. a bunch of time went into trying to implement proper playback caching, and i am glad to announce it was an absolute disaster. That aside, I made a pretty README! frankly, the best one I’ve made yet, full of screenshots and the such. I’ll probably be slowly trying to bundle the app for all platforms, and will be publishing the app fairly soon
No fancy speak again, it’s too early for that and I haven’t finished my coffe yet, but i finally made a homescreen to the app! I have made it configurable, so you can select which shelves to include on it, and i’ll be adding more configuration options later (i need some ideas here). Other than that i worked on some minor bug fixes, mostly layout based like mismatched padding, and finally set up a github CI to package the app, so you can now get it from the github’s releases page (i should probably test the windows build shouldn’t i?)
You wake up. You don’t remember a lot from last night; in fact, you aren’t really sure if you remember anything from the previous day. Regardless, you are filled with a overwhelming need to listen to something. Remembering only the title, you search for it, and in an instant your room if filled with soothing music, exactly the song you wanted. Listening to it slowly reminds you what happened on the previous day. Hey, i’ve gotten pretty good at writing these, anyway, I’ve added a global search function to the app, which searches through tracks, albums, artists, etc. all at once. I also did a * ton * of other small fixes and improvements. If you want to test out the app, You can get it from https://github.com/MHanak1/Yama/releases/latest
Soo, I did some more work, mostly on the desktop polishing front, anything from keyboard controls, to better Windows support and the ability to change the app theme through a file (for all of you spicers out there). Other than that, the one feature i’ve added is the ability to edit playlists, which has been missing for quite a while now.
Ships:
Well, the do-it-all * music app is done * * . It took longer than I expected, and i wasn’t able to squeeze in all of the features i wanted to add, but i’m still happy with the result. *okay, maybe not “all”, but quite a lot. **except for a bunch of features i’m hoping to add down the line....
|
1792997388.3454053
|
1793083788.3454053
|
|
59897
|
Loom by @kaveeshkrishna | Stardance
|
kaveeshkrishna
|
1
|
100.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-16T10:42:34Z", "hours": 100.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Loom is a self hosted file manager for your own server or NAS. You point it at a folder of photos, videos, and documents you already have and it gives you a proper web app to browse, search, and stream them from anywhere, without ever touching or reorganizing the actual files on disk. I built it because I have a Samsung T7 drive full of a decade of family photos and every app I tried wanted to import everything into its own library and rename stuff. Loom just reads whatever folder structure you already have and works with that. . Under the hood it’s three Docker containers, a Next.js app for the UI and API, a separate worker that indexes the filesystem and makes thumbnails, and Postgres for metadata only, never file content. It has a full file browser with grid and list views, a photo and video viewer, drag and drop uploads, trash with recovery, multiple user accounts with per folder permissions, and an audit log. There’s also a public demo you can try without installing anything, it’s a completely fake version running with no backend at all, everything happens in your browser. . The hardest part by far was video playback. Browsers only play a handful of video formats natively, so anything else, HEVC from an iphone, old MOV and AVI files, needed converting on the fly. I didn’t want to transcode an entire two hour video before someone could watch even the first second of it, so I built a system that only converts the exact chunk of video someone is actually watching or seeking to, in six second pieces, and shares the work if two people ask for the same part at once. Getting that to not corrupt itself when someone seeks around took a lot of debugging. . The other really annoying stretch was making the demo version work. It’s a static build with literally no server, and the entire fake backend is done by intercepting fetch requests in the browser. I got it fully built and deployed and it looked fine, every page loaded, every request returned 200, and it was completely broken underneath, folders showed up empty and buttons did nothing. Turned out the code that fakes the backend was never actually running in the browser at all because of how Next.js bundles server components, and curl and normal build checks couldn’t catch it since everything technically responded fine. I only found it by scripting an actual headless browser to click through the site. . What I’m most proud of is probably the idle drive design. A lot of self hosted apps for photos and files constantly watch your disk or hash every file on every scan, and I really didn’t want that for a drive that spins down. Loom only reads file size and modified time to check for changes, and only actually opens a file’s content the first time something genuinely needs to, like making a thumbnail. A full rescan of a library that hasn’t changed barely touches the disk at all. . To test it, the easiest way is the live demo, no install needed, any username and password works and there’s a button that fills in the demo login for you. From there you can click into the sample folders (they go a few levels deep on purpose), open a photo or video, try renaming or trashing something and refresh the page to see it stuck around, and check out the settings pages for users, permissions, and the scanner. If you want to run the real thing, it’s a single script install with Docker, clone the repo and run the install script and it walks you through the rest.", "repo": "https://github.com/KaveeshKrishna/loom", "demo": "https://loomdemo.kaveeshkrishna.in/"}]...
|
[{"post_id": 69058, "ts": "202 [{"post_id": 69058, "ts": "2026-09-16T09:40:09Z", "hours": 7.2369, "text": "DEVLOG_13: OKKK, so this is gonna be the last devlog for Loom before I ship it. Loom is now ready to be used by anyone in their VPS to manage their personal file :] . I also made a demo website for loom which anyone can visit to see how it works and looks at loomdemo.kaveeshkrishna.in . Fixed the last remaining bugs and made the permissions working properly, now every new account in Loom can be given a set of permissions and that account will not be able to access files other than the set permissions."}, {"post_id": 68572, "ts": "2026-09-15T10:33:23Z", "hours": 9.1325, "text": "DEVLOG_12: This was a long and major update session, I added a working notification system, if uploading files or downloading files or moving them causes any error, loom safely pauses the operation to avoid problems with the file and throws a notification stating what happened. Also other notifications like scan completion is also given :] . The file and folder upload features are actually working now, although it gets stuck when uploading very large files, I am trying to make it more reliable at the moment. . So let me explain how file upload actually works in loom, so when you upload a file it shows as uploaded on the screen but in the backend it stays in the internal storage of the vps, an automatic scan job is triggered for that file/folder, all the indexing and preview/thumbnail generation is completed and then the file/folder is transferred to the designated path. . File search now also works with the Photos, Videos, and Documents tabs."}, {"post_id": 68328, "ts": "2026-09-14T23:07:39Z", "hours": 7.9258, "text": "DEVLOG_11: OK!! so in this coding session I built a File Health page in Loom. This is a feature which I was personally excited to make :] . So basically while the Scan is running Loom tries to index files, generate preview and thumbnails for media files, if during this process any files throws error and Loom finds out the file is corrupt or has any issues it labels the issue and hides it from the file explorer and shows it in the dedicated File Health page. . At the moment it only displays these compromised files and shows the exact error they gave, but in the future I want to make Loom be able to fix these files if possible."}, {"post_id": 68019, "ts": "2026-09-14T12:02:43Z", "hours": 5.9486, "text": "DEVLOG_10: I have added a proper trash system. So any file you delete gets transferred to the .trash folder inside the same storage device and sits there for 15 days. if you don’t manually deleted them permanently, they get deleted automatically after 15 days. . Right now I am transferring all the deleted files and folders as it is to the trash, but I am thinking to make them compressed while storing inside the trash so that the don’t take up a lot of space, I haven’t implemented this though as I am not sure how am I gonna do it properly yet :]"}, {"post_id": 67577, "ts": "2026-09-13T18:32:50Z", "hours": 4.1153, "text": "DEVLOG_9: Ok now the Favorites, Photos, Videos and Documents pages are working properly. . In the Fav page all the files which we have starred are listed, and on the vid, photos and docs pages the respective kind of files are listed. . These specific pages are essentially acting like a filter filtering out specific files extensions from throughout the storage device and listing all of the filtered files in one place :]"}, {"post_id": 67370, "ts": "2026-09-13T13:36:45Z", "hours": 6.4731, "text": "DEVLOG_8: Added a proper folder path tree just like windows file explorer. It grows as you open folders inside folders and clicking on the previous folder name will take you to that folder. :] . I have made it properly responsive too, so if it grows too much the previous folders are replaced with “…”"}, {"post_id": 67116, "ts": "2026-09-13T05:34:18Z", "hours": 8.9731, "text": "DEVLOG_7: OK!! so this time I have added a few small but noticeable features!! . First, I added multiple file/folder selection and bulk actions like delete. . Second, I made the search work, so it searches in the current open directory by default and if you are on the home page then ofc it searches the entire storage device, but if you are in some other folder and you try searching it will by default search in that folder only if you want it to search the entire storage device then u can click on the little global search icon beside the search bar (it appears only when you are not in the home directory) And it is quite fast because it searches using the folder indexes stored in the database during scan. . Third, I added list view and in the grid view I added 4 different icon sizes, Small, Medium, Large, Extra Large. . And Finally, for all the right click actions, I added a long press action for touch screen devices :]"}, {"post_id": 66801, "ts": "2026-09-12T18:06:55Z", "hours": 8.07, "text": "DEVLOG_6: Ok, I don’t why it took me this long to implement but here we are _ I added right click action menu for folders, files and directory. right clicking on the empty space of current directory will give you options to upload files and folders and create folders (only create folder action works at the moment). And right clicking on folders and files will give you options like cut, paste, copy delete and star. Starring a file will add it to the favorites folder which can be accessed via the side panel and deleting anything will send it to the trash folder and it will be permanently deleted after 15 days. I am still working on making the proper UI of trash folder and fav folder :]"}, {"post_id": 66436, "ts": "2026-09-12T08:28:41Z", "hours": 12.1856, "text": "DEVLOG_5: Worked for 12+ hours straight and finally implemented a lot of very important features. The Scanner is now properly working there was a bug I solved which was making the scanner log the indexes of the files but never start a preview or thumbnail generation. Now each time U hit scan button it goes through the entire directory of your storage device and every file is properly indexed in a postgres database. every img file is sent to a thumbnail and preview generator and from every vid file its 1st second is captured and used to generate a thumbnail and preview for it as well. All these thumbnails and previews are stored in the internal ssd of the vps so that when you are scrolling throught the galary the main ssd is not touched and the user sees a lower quality thumbnail of every image and vid instead of loading the entire thing in full quality. To actually play vids on the browser, I’m using HLS Video Cache which lets me supply the vid to the user’s browser in chunks rather than the entire file at once, it makes the loading faster and playtime smooth. Lasty I also added an audit log page which shows the last 20 audits on done on Loom :]"}, {"post_id": 66079, "ts": "2026-09-11T17:28:39Z", "hours": 8.905, "text": "DEVLOG_4: In the settings page I have added the option to create new users with different permissions. I can decide which folders each account can see and what they can not see. Also, the Scanner page now lets me start a manual scan which will go through the storage device and index all the files properly. I am also working on an automatic Preview and Thumbnail generation while this scan runs but right now it is not working, hopegully by the next 2 Devlogs I can make it work :]"}, {"post_id": 65820, "ts": "2026-09-11T06:55:27Z", "hours": 6.3156, "text": "DEVLOG_3: After doing a lot of research online about industry standard says to make a secure login method. I added a login page that uses email and password, no Google OAuth because Loom is not supposed to be a public website but for personal use. I’m using better-auth for the actual logic. It hashes passwords with Scrypt so they are never stored in plain text, and it keeps sessions as a row in a sessions table plus a signed httpOnly cookie. The cookie is signed with BETTER_AUTH_SECRET which the installer generates as a random 48 byte value. Each sessions last 30 days and refresh if they are older than a day, so you dont get logged out mid use. CSRF is handled by TRUSTED_ORIGINS in the env, a list of origins allowed to make logged in requests, anything not on the list gets rejected :]"}, {"post_id": 65358, "ts": "2026-09-10T13:25:15Z", "hours": 5.6942, "text": "DEVLOG_2: This one took more time than I thought but now Loom is able to identify folder structure and files inside my SSD :] The scanner walks the tree with readdir and stat, and for every file it stores the path (relative to /media), the name, file or directory, the type, size and modified time. all of that becomes a FileNode row in Postgres."}, {"post_id": 64829, "ts": "2026-09-09T14:44:59Z", "hours": 9.1172, "text": "DEVLOG_1: After taking break from my project Sentinel, I have now started a new project Loom. It is again related to the home server I made using my 7 year old laptop!! I am making this project because I wanted a reliable way to access and edit personal files which are on an external ssd attached to my server. Everything remotely. Right now I have made the initial UI of Loom and a rough outline of where buttons and options are gonna be. now I am gonna work on all the different sections you are seeing on the attached image :]"}]...
|
Title: Loom by @kaveeshkrishna | Stardance
Devlog Title: Loom by @kaveeshkrishna | Stardance
Devlogs:
DEVLOG_1: After taking break from my project Sentinel, I have now started a new project Loom. It is again related to the home server I made using my 7 year old laptop!! I am making this project because I wanted a reliable way to access and edit personal files which are on an external ssd attached to my server. Everything remotely. Right now I have made the initial UI of Loom and a rough outline of where buttons and options are gonna be. now I am gonna work on all the different sections you are seeing on the attached image :]
DEVLOG_2: This one took more time than I thought but now Loom is able to identify folder structure and files inside my SSD :] The scanner walks the tree with readdir and stat, and for every file it stores the path (relative to /media), the name, file or directory, the type, size and modified time. all of that becomes a FileNode row in Postgres.
DEVLOG_3: After doing a lot of research online about industry standard says to make a secure login method. I added a login page that uses email and password, no Google OAuth because Loom is not supposed to be a public website but for personal use. I’m using better-auth for the actual logic. It hashes passwords with Scrypt so they are never stored in plain text, and it keeps sessions as a row in a sessions table plus a signed httpOnly cookie. The cookie is signed with BETTER_AUTH_SECRET which the installer generates as a random 48 byte value. Each sessions last 30 days and refresh if they are older than a day, so you dont get logged out mid use. CSRF is handled by TRUSTED_ORIGINS in the env, a list of origins allowed to make logged in requests, anything not on the list gets rejected :]
DEVLOG_4: In the settings page I have added the option to create new users with different permissions. I can decide which folders each account can see and what they can not see. Also, the Scanner page now lets me start a manual scan which will go through the storage device and index all the files properly. I am also working on an automatic Preview and Thumbnail generation while this scan runs but right now it is not working, hopegully by the next 2 Devlogs I can make it work :]
DEVLOG_5: Worked for 12+ hours straight and finally implemented a lot of very important features. The Scanner is now properly working there was a bug I solved which was making the scanner log the indexes of the files but never start a preview or thumbnail generation. Now each time U hit scan button it goes through the entire directory of your storage device and every file is properly indexed in a postgres database. every img file is sent to a thumbnail and preview generator and from every vid file its 1st second is captured and used to generate a thumbnail and preview for it as well. All these thumbnails and previews are stored in the internal ssd of the vps so that when you are scrolling throught the galary the main ssd is not touched and the user sees a lower quality thumbnail of every image and vid instead of loading the entire thing in full quality. To actually play vids on the browser, I’m using HLS Video Cache which lets me supply the vid to the user’s browser in chunks rather than the entire file at once, it makes the loading faster and playtime smooth. Lasty I also added an audit log page which shows the last 20 audits on done on Loom :]
DEVLOG_6: Ok, I don’t why it took me this long to implement but here we are _ I added right click action menu for folders, files and directory. right clicking on the empty space of current directory will give you options to upload files and folders and create folders (only create folder action works at the moment). And right clicking on folders and files will give you options like cut, paste, copy delete and star. Starring a file will add it to the favorites folder which can be accessed via the side panel and deleting anything will send it to the trash folder and it will be permanently deleted after 15 days. I am still working on making the proper UI of trash folder and fav folder :]
DEVLOG_7: OK!! so this time I have added a few small but noticeable features!! . First, I added multiple file/folder selection and bulk actions like delete. . Second, I made the search work, so it searches in the current open directory by default and if you are on the home page then ofc it searches the entire storage device, but if you are in some other folder and you try searching it will by default search in that folder only if you want it to search the entire storage device then u can click on the little global search icon beside the search bar (it appears only when you are not in the home directory) And it is quite fast because it searches using the folder indexes stored in the database during scan. . Third, I added list view and in the grid view I added 4 different icon sizes, Small, Medium, Large, Extra Large. . And Finally, for all the right click actions, I added a long press action for touch screen devices :]
DEVLOG_8: Added a proper folder path tree just like windows file explorer. It grows as you open folders inside folders and clicking on the previous folder name will take you to that folder. :] . I have made it properly responsive too, so if it grows too much the previous folders are replaced with “…”
DEVLOG_9: Ok now the Favorites, Photos, Videos and Documents pages are working properly. . In the Fav page all the files which we have starred are listed, and on the vid, photos and docs pages the respective kind of files are listed. . These specific pages are essentially acting like a filter filtering out specific files extensions from throughout the storage device and listing all of the filtered files in one place :]
DEVLOG_10: I have added a proper trash system. So any file you delete gets transferred to the .trash folder inside the same storage device and sits there for 15 days. if you don’t manually deleted them permanently, they get deleted automatically after 15 days. . Right now I am transferring all the deleted files and folders as it is to the trash, but I am thinking to make them compressed while storing inside the trash so that the don’t take up a lot of space, I haven’t implemented this though as I am not sure how am I gonna do it properly yet :]
DEVLOG_11: OK!! so in this coding session I built a File Health page in Loom. This is a feature which I was personally excited to make :] . So basically while the Scan is running Loom tries to index files, generate preview and thumbnails for media files, if during this process any files throws error and Loom finds out the file is corrupt or has any issues it labels the issue and hides it from the file explorer and shows it in the dedicated File Health page. . At the moment it only displays these compromised files and shows the exact error they gave, but in the future I want to make Loom be able to fix these files if possible.
DEVLOG_12: This was a long and major update session, I added a working notification system, if uploading files or downloading files or moving them causes any error, loom safely pauses the operation to avoid problems with the file and throws a notification stating what happened. Also other notifications like scan completion is also given :] . The file and folder upload features are actually working now, although it gets stuck when uploading very large files, I am trying to make it more reliable at the moment. . So let me explain how file upload actually works in loom, so when you upload a file it shows as uploaded on the screen but in the backend it stays in the internal storage of the vps, an automatic scan job is triggered for that file/folder, all the indexing and preview/thumbnail generation is completed and then the file/folder is transferred to the designated path. . File search now also works with the Photos, Videos, and Documents tabs.
DEVLOG_13: OKKK, so this is gonna be the last devlog for Loom before I ship it. Loom is now ready to be used by anyone in their VPS to manage their personal file :] . I also made a demo website for loom which anyone can visit to see how it works and looks at loomdemo.kaveeshkrishna.in . Fixed the last remaining bugs and made the permissions working properly, now every new account in Loom can be given a set of permissions and that account will not be able to access files other than the set permissions.
Ships:
Loom is a self hosted file manager for your own server or NAS. You point it at a folder of photos, videos, and documents you already have and it gives you a proper web app to browse, search, and stream them from anywhere, without ever touching or reorganizing the actual files on disk. I built it because I have a Samsung T7 drive full of a decade of family photos and every app I tried wanted to import everything into its own library and rename stuff. Loom just reads whatever folder structure you already have and works with that. . Under the hood it’s three Docker containers, a Next.js app for the UI and API, a separate worker that indexes the filesystem and makes thumbnails, and Postgres for metadata only, never file content. It has a full file browser with grid and list views, a photo and video viewer, drag and drop uploads, trash with recovery, multiple user accounts with per folder permissions, and an audit log. There’s also a public demo you can try without installing anything, it’s a completely fake version running with no backend at all, everything happens in your browser. . The hardest part by far was video playback. Browsers only play a handful of video formats natively, so anything else, HEVC from an iphone, old MOV and AVI files, needed converting on the fly. I didn’t want to transcode an entire two hour video before someone could watch even the first second of it, so I built a system that only converts the exact chunk of video someone is actually watching or seeking to, in six second pieces, and shares the work if two people ask for the same part at once. Getting that to not corrupt itself when someone seeks around took a lot of debugging. . The other really annoying stretch was making the demo version work. It’s a static build with literally no server, and the entire fake backend is done by intercepting fetch requests in the browser. I got it fully built and deployed and it looked fine, every page loaded, every request returned 200, and it was completely broken underneath, folders showed up empty and buttons did nothing. Turned out the code that fakes the backend was never actually running in the browser at all because of how Next.js bundles server components, and curl and normal build checks couldn’t catch it since everything technically responded fine. I only found it by scripting an actual headless browser to click through the site. . What I’m most proud of is probably the idle drive design. A lot of self hosted apps for photos and files constantly watch your disk or hash every file on every scan, and I really didn’t want that for a drive that spins down. Loom only reads file size and modified time to check for changes, and only actually opens a file’s content the first time something genuinely needs to, like making a thumbnail. A full rescan of a library that hasn’t changed barely touches the disk at all. . To test it, the easiest way is the live demo, no install needed, any username and password works and there’s a button that fills in the demo login for you. From there you can click into the sample folders (they go a few levels deep on purpose), open a photo or video, try renaming or trashing something and refresh the page to see it stuck around, and check out the settings pages for users, permissions, and the scanner. If you want to run the real thing, it’s a single script install with Docker, clone the repo and run the install script and it walks you through the rest....
|
1793055101.512431
|
1793141501.512431
|
|
41081
|
X by @ManoX | Stardance
|
ManoX
|
3
|
99.88
|
1274
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-25T17:20:40Z", "hours": 40.0, "multiplier": 14.9, "payout": 543, "blessing": "neutral", "text": "Ship #3 - X is pre-production ready X is a full-stack React framework written natively in Bun. It has seen 90+h development and is at the point where I can hand it over to someone else and walk away. What’s in the box • File-based routing with SSR, SSG, ISR - pick per route • Islands architecture for client interactivity, no more use client • Server functions, which at build-time are rewritten to fetch wrappers • Authentication package with credentials + OAuth2, sessions, CSRF, brute-force protection, RBAC • Build-time environment leakage check, implemented as an AST visitor that fails the build on a secret accidental exposure • Adapter for Vercel that generates a .vercel/output directory with static CDN and serverless SSR • MCP server for training AI agents that write correct x applications, not hallucinating Next.js code • Structured JSON logs, /healthz, /readyz, OpenTelemetry/Sentry hooks • Docker builds with explicit workspace COPY gates and CVE scanning at build-time What’s been fixed in this cycle: • SQLite session store did not observe created_at on relogin, unlike Postgres • The AuthGuardResult object had { ok: ‘success’, status: 401 } shape on successful auth guard resolution, has been renamed to a discriminated union type to avoid carrying stale data • The Vercel adapter accepted comma-joined X-Forwarded-For headers that should have been rejected • The auth package had code duplication between brute-force protection and audit logging for parsing X-Forwarded-For, consolidated into a clientIpFromRequest util • The hero component on the landing page broke on actual mobile viewports - fixed a responsive slab assumption in the install command component • Docs had foreign framework artifacts (use client directives, wrong loader signatures), all scrubbed CI is properly set up now, only merged branches push changes. For every PR: • TypeScript checks, Biome linting, tests run on Ubuntu/macOS • Postgres migration checks, Docker builds with CVE scans • Package audits (using a sha256-pinned manifest), load-testing with SLOs • Vercel preview deploys, changeset validation for monorepo packages No automatic merging - everything is watched by the repo until the CI turns green and the PR is squashed. Repo: https://github.com/abdelkabirouadoukou/x Docs: https://thexjs.abdelkabir.me/", "repo": "https://github.com/abdelkabirouadoukou/x", "demo": "https://thexjs.abdelkabir.me/"}, {"ship_num": 2, "ts": "2026-08-13T11:57:23Z", "hours": 49.0, "multiplier": 16.15, "payout": 720, "blessing": "neutral", "text": "Ship #2 is finally done after 50+ hours. Shipped build-time secret leak protection, Vercel deployments, structured logging, and a 100/100 PageSpeed landing page redesign. Check the repo for all the devlogs!", "repo": "https://github.com/abdelkabirouadoukou/x", "demo": "https://thexjs.abdelkabir.me/"}, {"ship_num": 3, "ts": "2026-07-29T08:20:41Z", "hours": 2.0, "multiplier": 5.0, "payout": 11, "blessing": "neutral", "text": "Built “X” — a lightweight full-stack React framework powered natively by the Bun runtime. In this update, I focused on getting the core Server-Side Rendering (SSR) pipeline smooth and ultra-fast. I refactored the dev server to make hot-reloading seamless, fixed routing edge cases, and polished the CLI so you can spin up a full-stack React app with zero-config overhead. The goal is to keep modern React development fast, simple, and bloat-free by leveraging Bun’s speed.", "repo": "https://github.com/abdelkabirouadoukou/x", "demo": "https://thexjs.abdelkabir.me/"}]...
|
[{"post_id": 56299, "ts": "202 [{"post_id": 56299, "ts": "2026-08-28T00:54:57Z", "hours": 8.8839, "text": "I will update this post soon.."}, {"post_id": 54609, "ts": "2026-08-25T17:08:22Z", "hours": 1.0106, "text": "Devlog #13 Fixed two critical auth bugs, both related to the auth package; the fixes are already in the PRs (not merged yet, waiting for CI). sqlite session store silently overwritten created_at (#175) Postgres store used ON CONFLICT (token) DO UPDATE, which does not update created_at column on purpose; therefore, on each re-login with the same token, the created_at would remain the same, signifying that the session was created at the same time. However, the sqlite had a different approach of INSERT OR REPLACE which replaced the whole row, including created_at. This PR changes the sqlite version to use the explicit upsert so that both databases behave the same way. Also adds a regression test that purposely creates a session, re-logins with the same token/data and checks that created_at was not changed. The postgres tests are skipped for local DATABASE_URL absent. AuthGuardResult lied on success (#177) AuthGuardResult was a type { ok: boolean; status: 401 | 403; reason: string }, and on success, the guard returned { ok: true, status: 401, reason: “” }, i.e., a 401 status code with an empty reason string. It was not a problem because toMiddleware always checked result.ok first, but it was a silent bug for anyone who tried to check result.status on success. Now it is properly represented as a discriminated union type { ok: true } | { ok: false; status: 401 | 403; reason: string }, and the status and reason fields are not present on success. All tests were adjusted to narrow the type with if (!result.ok) { … }, and a new test checks that TypeScript actually narrows the type."}, {"post_id": 54536, "ts": "2026-08-25T15:47:21Z", "hours": 5.0458, "text": "Devlog #12 this cycle was about mostly about closing the loop from “framework that works” to “framework someone else can actually adopt without me hovering nearby” Most importantly, agents can now understand x every dev I know, including senior devs, is now asking AI to write code for them. AI doesn’t know x conventions and will confidently write next.js or remix code that looks right but isn’t. So I released @thexjs /mcp - an MCP server for claude code, cursor and other agents that gives them concrete documentation for routing, loaders, server functions, env vars, and a scaffold_file tool that generates files in the right shape rather than the agent making up whatever it wants. This gets automatically added to any new project via .mcp.json / .cursor/mcp.json, and there’s also an llms.txt file on the docs for agents that just browse the site. They’re both generated from the same source so they can’t diverge. The docs got a much needed love, not just in terms of content I added the missing @thexjs /mcp docs page, and got it linked into the sidebar/footer/search index (it was in the code but not easy to find). I also fixed some copy that had diverged from the actual implementation, including a docs page that suggested using “use client” directives that the framework doesn’t actually support. The landing page also got some updates The hero section is now properly responsive (it broke on real phones, not just narrow desktops). There was a bug where the docs sidebar was supposed to be sticky but wasn’t - fixed that (turns out it was an ancestor issue, not the sticky style itself). Copy was de-genericized a bit, since it was previously very similar to other dev tool landing pages. Some internal improvements I fixed a bug in the vercel adapter relating to forwarded-header hostname validation, and made some improvements to the scaffolder (shadcn wasn’t being installed when tailwind was automatically enabled, doctor’s semver range checks were actually checking the ranges, etc). I’m now using proper feature branches + PRs for everything rather than pushing to main directly. It’s more work but should avoid situations where, say, the docs get updated to disagree with the framework in confusing ways. If you want more details on any of this, check my repo!!"}, {"post_id": 53664, "ts": "2026-08-24T10:17:25Z", "hours": 3.4794, "text": "This post will be updated soon.."}, {"post_id": 51202, "ts": "2026-08-20T18:33:34Z", "hours": 8.7919, "text": "I will update this post with all fixes and fetaures i did [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!"}, {"post_id": 50140, "ts": "2026-08-19T07:36:27Z", "hours": 8.1294, "text": "I will update this post with all fixes and fetaures i did [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!"}, {"post_id": 49634, "ts": "2026-08-18T14:59:13Z", "hours": 13.5803, "text": "A loot of update i did plz check my repo to see them all [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!"}, {"post_id": 43975, "ts": "2026-08-09T13:31:41Z", "hours": 8.6686, "text": "Devlog #11 I found that browsers automatically remove tabs and newlines from a URL before checking its scheme, whereas my regex did not, and hence, I missed that javascript URLs could still bypass the sanitization and that is why they still worked. It ended up being part of releases 1.1.0 and 1.2.0. Also, I discovered that when checking whether environment leakage exists (build command is “x build”), this check silently fails without any message if environment is indeed leaky secrets get masked properly but “x build” exits with 0 and therefore CI never discovers that a feature has quietly malfunctioned. This time, the patches for both of these issues have been made properly and checked manually before merging. Roadmap backlog has been taken care of after that. The items are a real end-to-end RBAC example, Redis multi-replica soak test, which would stress the multi-db system in a very large-scale environment; and a time when the security disclosure SLA is truly acted out in real life scenario not just being a paper trail."}, {"post_id": 43364, "ts": "2026-08-08T15:55:01Z", "hours": 5.4342, "text": "Development Blog #10 I spent most of my time working on the documentation backlog of adding new features. The @thexjs /auth was released a blogs ago but I still had not done the documentation for it. We did not have a page for this and some old references were no longer working in other parts of the application. I made a page for /docs/packages/auth on the website. This page has instructions, information about the endpoints and details about CSRF. I also added links to this page from the data-layer and security pages so I do not have to repeat the information in many places. I also started working on the testing gaps that were on the roadmap and marked as “beta” or “not tested”. This includes things like what happens when Postgres is not working problems with authorization and limits for instances using Redis. I changed the way I work on changes. Of making all the changes in the main branch I now make a separate branch, for each change and then open a pull request. This is a way to do things so I will keep doing it this way."}, {"post_id": 41058, "ts": "2026-08-05T00:38:01Z", "hours": 1.7586, "text": "DevLog #9 I ran PageSpeed Insights on the x landing page and obtained the following results: 100 for performance, 100 for accessibility, 100 for best practices, 91 for SEO on desktop, and 96, 100, 100, and 91 on mobile. For a page that makes no use of any framework-level image optimization or lazy-loading techniquesinstead it’s just a monochrome static page built with Bun the SEO score of 91 is likely due to the fact that I haven’t yet added the meta tags; all the other aspects are clean. Built with x: https://github.com/abdelkabirouadoukou/x"}, {"post_id": 41017, "ts": "2026-08-04T22:18:29Z", "hours": 7.6453, "text": "Devlog #8 I redesigned the landing page. It is now black and white with no color at all. I reduced the boot animation from about 5.5 seconds to 4 seconds. CI now runs “bun run build” and a format check on every PR, not just typecheck, lint, and tests. I rewrote most of the docs to reflect reality. There are new pages for Islands, ISR, catch-all routes, batch server-function registration, and CLI flags. I fixed several issues that had occurred, including the wrong RouteProps type, bad apiDir docs, and incorrect 404/middleware behavior. Code blocks now use a monochrome token palette that matches the new design. I also fixed an actual bug. The rate limiter used a shared “unknown” bucket when proxy headers were missing. This meant one client’s burst could cause a 429 error for everyone else. Now it uses the correct socket IP first. I also corrected the missing content-type in the 429 response, which was causing issues with static assets in some browsers."}, {"post_id": 38644, "ts": "2026-08-01T04:33:59Z", "hours": 3.1678, "text": "Devlog #7: clean audits, fixed styling, faster boarding passes This round was about tightening things up. The dependency audit is finally clean with zero ignores. There are no more accepted-risk advisories in CI. Just real fixes: pinned overrides on esbuild and @hono /node-server, and moving shadcn out of production dependencies where it never belonged. I also fixed a frustrating Vercel bug where deployed pages lost their stylesheet. It turns out existsSync doesn’t work the way you’d expect inside a serverless bundle. Now, the CSS href gets included at build time instead of being guessed at runtime. Smaller wins: I swapped the landing page fonts to Space Grotesk, Inter, and JetBrains Mono (all self-hosted, no Google Fonts), fixed a boarding-pass demo bug where signed bit shifts were producing -6undefined seat numbers, and cleaned up lint/typecheck across the workspace. Repo (⭐ appreciated): https://github.com/abdelkabirouadoukou/x Website: https://thexjs.vercel.app/"}, {"post_id": 38288, "ts": "2026-07-31T16:29:57Z", "hours": 14.9219, "text": "Log entry #6: on the day React’s own dispatcher attempted to become window.dispatchEvent Today six items were shipped; one took a lot longer to track down than it should have. The bug: clicking search crashed the site, but only in production Click the search bar, and the command palette should appear. Instead, the deployed build produced: Cannot read properties of undefined (reading ‘target’) Deep inside React’s event system. Not during development. Only in production. It has now been discovered that the island bundle is shipped as a classic rather than as a module, as a result, top-level declarations end up on the window object. In the minified bundle there was a top-level function called dispatchEvent: this was React DOM’s internal event dispatcher, having the same name as the browser’s actual dispatchEvent function, and it quietly overwritten window.dispatchEvent. The search trigger causes a synthetic ⌘K keydown event to be sent to the window in order to activate the palette island. It was doing this by calling React’s internal dispatcher with a raw keydown event and without a nativeEvent, which caused React to fail when it tried to read .target from an object of the incorrect shape. Solution: wrap each emitted island bundle (including the build output and the dev path) in an IIFE so that no top-level declaration now reaches the window object at all. This has been tested to ensure it works correctly. Nested layouts were rendering inside-out The _layout.tsx files contained within the route folders were behaving incorrectly by having the section layout wrap the root rather than the reverse. In order to correct this, the wrap order was reversed in the function renderPageWithLayout so that the root always remains the outermost element. Hydration mismatches stopped spamming the console Islands that have a non-deterministic initial state (mostly games) will always cause a mismatch with SSR output; although React handles the situation without any problems by re-rendering on the client side, each mismatch is still logged as a full error which could in turn spread through the event system. A no-op function was passed to the onRecoverableError handler so that these errors fail silently. Shipped: ⌘K command palette + a konami code easter egg The fuzzy-search palette is now its own island with React as its root, appearing through the same synthetic keydown event that brought up the bug mentioned above (as usual, dogfooding), and I’ve also included a Konami code easter egg. Vercel adapter The x build –adapter vercel now produces a proper .vercel/output in accordance with Vercel’s Build Output API, including the static HTML and island chunks as well as a bundled serverless render function. The route preloading and createApp have been adjusted so that the behaviour of the static and serverless versions matches that of local development. The packages/adapter-vercel have been divided into their own workspace package. Landing redesign + /play New styles, fonts, loading states, and the logo on the docs site. The bigger addition is the /play feature, which turns the framework into a small arcade—route matching treated as a game, an interactive environment leak-protection demonstration, and a static-versus-server call behaviour that you can click through. Two components have already been developed: leak-check (to provide a visual indication of the client/server boundary) and mode-call (comparing static and server rendering side by side). There are six fixes, one adapter, one new page, and a bug resulting from two functions sharing a name rather too casually. Tomorrow: it will probably be more of the same."}, {"post_id": 37586, "ts": "2026-07-30T12:47:06Z", "hours": 4.4567, "text": "Devlog #5: why I built x This all began when I was trying to launch my SaaS, autopermit (autopermit.vercel.app). whenever I clicked anything in Vercel’s dashboard, it was slow to respond. I had previously worked with Astro and built a simple blog. That was a good learning experience, and I liked the speed of the frontend framework. however, I wanted strong backend performance like Next.js offered. I knew I could combine the backend of Next.js with the frontend of Astro, but I wasn’t sure how to make it work for me or why I needed to do it. Then I found Bun, and everything became clear. Bun provided many important features right out of the box: bundler, runtime engine, package manager, and embedded database drivers. i realized i didn’t need to try to combine two heavyweight frameworks anymore. Github Repo (Give it Star ⭐️): https://github.com/abdelkabirouadoukou/x Website of FrameWork: https://thexjs.vercel.app/"}, {"post_id": 37122, "ts": "2026-07-29T16:39:39Z", "hours": 2.5361, "text": "DevLog #4 I’ve built x ( @thexjs ), a single-process, full-stack React framework which runs native on Bun. Project’s on StarDance: https://stardance.hackclub.com/home Why Next.js and the other tools come with Webpack or Vite, together with a development server and a lot of additional abstractions. Bun has already incorporated transpiling, bundling, package management, and native HTTP support , it even includes support for SQLite and Postgres. Which is why, rather than wrapping React around another bundler, I have built it to work directly with what Bun already provides. What it does The system is based on files just place a .tsx file in the src/pages/ directory and it becomes a route. Each route individually chooses whether to use SSR or static pre-rendering (by using the statement export const mode = “static”). The API routes are located in src/api/ and share their memory and database context with the rest of the application. Server functions enable you to call type-safe backend logic directly from within a component. Regarding security, there is build-time leak detection based on AST so that secrets won’t end up in the client bundles, together with CSRF protection and rate limiting built in. For use in production, /healthz and /readyz are provided, along with JSON logging and support for OpenTelemetry and Sentry. The application can be deployed to a VPS, using Docker, or on Vercel via @thexjs /adapter-vercel. Quickstart bash bun create thexjs-app@latest my-app cd my-app bun run dev You get a working app in less than a minute. Link: https://github.com/abdelkabirouadoukou/x If you look around and happen upon anything that’s broken, then open an issue I’ll look into it."}, {"post_id": 36944, "ts": "2026-07-29T10:58:23Z", "hours": 0.8828, "text": "Dev log #3 Shipped new features for x this week: a Vercel adapter, a real security layer, and observability that doesn’t depend on console.log. Vercel adapter ( @thexjs /adapter-vercel) Deploying to Vercel used to require dealing with vercel.json or using runtime hacks. The adapter now connects directly to the build pipeline and creates a proper .vercel/output/ directory. Static hydration bundles and media go to the CDN. SSR routes and server actions get packaged into a standalone Node-compatible ESM function. A config.json manifest directs static files first with SSR as the backup. No configuration is needed. Security @thexjs /core now checks client bundles during the build. If a server-only environment variable, such as STRIPE_SECRET_KEY, slips through without the THEXJS_PUBLIC_ prefix, the build fails immediately—preventing any leaks. Server actions reaching /__x/actions/* get automatic Origin/Referer verification with support for double-submit cookies to protect against CSRF. There’s also built-in CSP, HSTS, and X-Frame-Options headers, along with a customizable in-memory rate limiter. Observability Logs are now structured as JSON, including timestamp, requestId, status, and durationMs. This format works with Datadog, Loki, or Grafana without needing to parse raw text. Added /healthz and /readyz endpoints run before route matching, for those using this in Kubernetes. The createSentryReporter and createOtelReporter hooks automatically catch unhandled SSR and action errors. Config example: import { createApp , createSentryReporter } from \" @thexjs/core \" ; const app = createApp ({ pagesDir : \" ./src/pages \" , actionsDir : \" ./src/actions \" , security : { csrf : { allowedOrigins : [ \" https://app.example.com \" ] }, headers : { contentSecurityPolicy : \" default-src 'self' \" }, rateLimit : { limit : 100 , windowMs : 60 _000 }, }, observability : { logging : true , errorReporter : createSentryReporter ( Sentry ), health : { checks : { database : () => db . ping () } }, }, }); Still working through the rest of the PRD. Routing, i18n, and caching are next."}, {"post_id": 36888, "ts": "2026-07-29T08:19:21Z", "hours": 1.6447, "text": "Dev log #2 Log entry: I’ve been working over the past few days on SSR performance and sorting out the DX side. I reduced the initial size of the payload and altered the way components hydrate, which as a result decreased response latency on the native Bun HTTP server. I refactored the startup CLI and improved hot module reloading, file changes now appear instantly rather than sometimes needing a restart. A routing bug involving the parsing of query parameters which was causing problems with the serving of static assets in certain situations has also been fixed, and the way in which internal state is managed throughout the request lifecycle has been cleaned up. What was annoying was the situation with concurrent requests when doing hot reloads since Bun would leave the state hanging between reloads, a problem that only became apparent under heavy load. It took some time to work out what was going on and in the end I added more detailed logging to detect the cases where the memory wasn’t being freed. The server now runs cleanly without the need for manual restarts, which was the real aim."}, {"post_id": 36836, "ts": "2026-07-29T04:32:21Z", "hours": 0.5161, "text": "Dev log #1 Shipped x (TheXJS) to npm. It’s a full-stack React framework built on Bun. I wanted server-side rendering that truly takes advantage of Bun’s runtime instead of just running on top of it like everything else does. It’s a monorepo. The core engine and CLI are separate packages, so you won’t pull in tools you don’t need. The command bun create thexjs-app sets up a working project in one step. The documentation is live at the link below, and I’m still filling in gaps as I go. Live demo & docs: https://thexjs.vercel.app/ npm: https://www.npmjs.com/~abdelkabirouadoukou create-thexjs-app: https://www.npmjs.com/package/create-thexjs-app @thexjs /core: https://www.npmjs.com/package/@thexjs/core @thexjs /env: https://www.npmjs.com/package/@thexjs/env @thexjs /cli: https://www.npmjs.com/package/@thexjs/cli Repo: https://github.com/abdelkabirouadoukou/x If you try it and something breaks, let me know. That’s the fastest way for me to fix it."}]...
|
Title: X by @ManoX | Stardance
Devlogs:
Dev log # Title: X by @ManoX | Stardance
Devlogs:
Dev log #1 Shipped x (TheXJS) to npm. It’s a full-stack React framework built on Bun. I wanted server-side rendering that truly takes advantage of Bun’s runtime instead of just running on top of it like everything else does. It’s a monorepo. The core engine and CLI are separate packages, so you won’t pull in tools you don’t need. The command bun create thexjs-app sets up a working project in one step. The documentation is live at the link below, and I’m still filling in gaps as I go. Live demo & docs: https://thexjs.vercel.app/ npm: https://www.npmjs.com/~abdelkabirouadoukou create-thexjs-app: https://www.npmjs.com/package/create-thexjs-app @thexjs /core: https://www.npmjs.com/package/@thexjs/core @thexjs /env: https://www.npmjs.com/package/@thexjs/env @thexjs /cli: https://www.npmjs.com/package/@thexjs/cli Repo: https://github.com/abdelkabirouadoukou/x If you try it and something breaks, let me know. That’s the fastest way for me to fix it.
Dev log #2 Log entry: I’ve been working over the past few days on SSR performance and sorting out the DX side. I reduced the initial size of the payload and altered the way components hydrate, which as a result decreased response latency on the native Bun HTTP server. I refactored the startup CLI and improved hot module reloading, file changes now appear instantly rather than sometimes needing a restart. A routing bug involving the parsing of query parameters which was causing problems with the serving of static assets in certain situations has also been fixed, and the way in which internal state is managed throughout the request lifecycle has been cleaned up. What was annoying was the situation with concurrent requests when doing hot reloads since Bun would leave the state hanging between reloads, a problem that only became apparent under heavy load. It took some time to work out what was going on and in the end I added more detailed logging to detect the cases where the memory wasn’t being freed. The server now runs cleanly without the need for manual restarts, which was the real aim.
Dev log #3 Shipped new features for x this week: a Vercel adapter, a real security layer, and observability that doesn’t depend on console.log. Vercel adapter ( @thexjs /adapter-vercel) Deploying to Vercel used to require dealing with vercel.json or using runtime hacks. The adapter now connects directly to the build pipeline and creates a proper .vercel/output/ directory. Static hydration bundles and media go to the CDN. SSR routes and server actions get packaged into a standalone Node-compatible ESM function. A config.json manifest directs static files first with SSR as the backup. No configuration is needed. Security @thexjs /core now checks client bundles during the build. If a server-only environment variable, such as STRIPE_SECRET_KEY, slips through without the THEXJS_PUBLIC_ prefix, the build fails immediately—preventing any leaks. Server actions reaching /__x/actions/* get automatic Origin/Referer verification with support for double-submit cookies to protect against CSRF. There’s also built-in CSP, HSTS, and X-Frame-Options headers, along with a customizable in-memory rate limiter. Observability Logs are now structured as JSON, including timestamp, requestId, status, and durationMs. This format works with Datadog, Loki, or Grafana without needing to parse raw text. Added /healthz and /readyz endpoints run before route matching, for those using this in Kubernetes. The createSentryReporter and createOtelReporter hooks automatically catch unhandled SSR and action errors. Config example: import { createApp , createSentryReporter } from " @thexjs/core " ; const app = createApp ({ pagesDir : " ./src/pages " , actionsDir : " ./src/actions " , security : { csrf : { allowedOrigins : [ " https://app.example.com " ] }, headers : { contentSecurityPolicy : " default-src 'self' " }, rateLimit : { limit : 100 , windowMs : 60 _000 }, }, observability : { logging : true , errorReporter : createSentryReporter ( Sentry ), health : { checks : { database : () => db . ping () } }, }, }); Still working through the rest of the PRD. Routing, i18n, and caching are next.
DevLog #4 I’ve built x ( @thexjs ), a single-process, full-stack React framework which runs native on Bun. Project’s on StarDance: https://stardance.hackclub.com/home Why Next.js and the other tools come with Webpack or Vite, together with a development server and a lot of additional abstractions. Bun has already incorporated transpiling, bundling, package management, and native HTTP support , it even includes support for SQLite and Postgres. Which is why, rather than wrapping React around another bundler, I have built it to work directly with what Bun already provides. What it does The system is based on files just place a .tsx file in the src/pages/ directory and it becomes a route. Each route individually chooses whether to use SSR or static pre-rendering (by using the statement export const mode = “static”). The API routes are located in src/api/ and share their memory and database context with the rest of the application. Server functions enable you to call type-safe backend logic directly from within a component. Regarding security, there is build-time leak detection based on AST so that secrets won’t end up in the client bundles, together with CSRF protection and rate limiting built in. For use in production, /healthz and /readyz are provided, along with JSON logging and support for OpenTelemetry and Sentry. The application can be deployed to a VPS, using Docker, or on Vercel via @thexjs /adapter-vercel. Quickstart bash bun create thexjs-app@latest my-app cd my-app bun run dev You get a working app in less than a minute. Link: https://github.com/abdelkabirouadoukou/x If you look around and happen upon anything that’s broken, then open an issue I’ll look into it.
Devlog #5: why I built x This all began when I was trying to launch my SaaS, autopermit (autopermit.vercel.app). whenever I clicked anything in Vercel’s dashboard, it was slow to respond. I had previously worked with Astro and built a simple blog. That was a good learning experience, and I liked the speed of the frontend framework. however, I wanted strong backend performance like Next.js offered. I knew I could combine the backend of Next.js with the frontend of Astro, but I wasn’t sure how to make it work for me or why I needed to do it. Then I found Bun, and everything became clear. Bun provided many important features right out of the box: bundler, runtime engine, package manager, and embedded database drivers. i realized i didn’t need to try to combine two heavyweight frameworks anymore. Github Repo (Give it Star ⭐️): https://github.com/abdelkabirouadoukou/x Website of FrameWork: https://thexjs.vercel.app/
Log entry #6: on the day React’s own dispatcher attempted to become window.dispatchEvent Today six items were shipped; one took a lot longer to track down than it should have. The bug: clicking search crashed the site, but only in production Click the search bar, and the command palette should appear. Instead, the deployed build produced: Cannot read properties of undefined (reading ‘target’) Deep inside React’s event system. Not during development. Only in production. It has now been discovered that the island bundle is shipped as a classic rather than as a module, as a result, top-level declarations end up on the window object. In the minified bundle there was a top-level function called dispatchEvent: this was React DOM’s internal event dispatcher, having the same name as the browser’s actual dispatchEvent function, and it quietly overwritten window.dispatchEvent. The search trigger causes a synthetic ⌘K keydown event to be sent to the window in order to activate the palette island. It was doing this by calling React’s internal dispatcher with a raw keydown event and without a nativeEvent, which caused React to fail when it tried to read .target from an object of the incorrect shape. Solution: wrap each emitted island bundle (including the build output and the dev path) in an IIFE so that no top-level declaration now reaches the window object at all. This has been tested to ensure it works correctly. Nested layouts were rendering inside-out The _layout.tsx files contained within the route folders were behaving incorrectly by having the section layout wrap the root rather than the reverse. In order to correct this, the wrap order was reversed in the function renderPageWithLayout so that the root always remains the outermost element. Hydration mismatches stopped spamming the console Islands that have a non-deterministic initial state (mostly games) will always cause a mismatch with SSR output; although React handles the situation without any problems by re-rendering on the client side, each mismatch is still logged as a full error which could in turn spread through the event system. A no-op function was passed to the onRecoverableError handler so that these errors fail silently. Shipped: ⌘K command palette + a konami code easter egg The fuzzy-search palette is now its own island with React as its root, appearing through the same synthetic keydown event that brought up the bug mentioned above (as usual, dogfooding), and I’ve also included a Konami code easter egg. Vercel adapter The x build –adapter vercel now produces a proper .vercel/output in accordance with Vercel’s Build Output API, including the static HTML and island chunks as well as a bundled serverless render function. The route preloading and createApp have been adjusted so that the behaviour of the static and serverless versions matches that of local development. The packages/adapter-vercel have been divided into their own workspace package. Landing redesign + /play New styles, fonts, loading states, and the logo on the docs site. The bigger addition is the /play feature, which turns the framework into a small arcade—route matching treated as a game, an interactive environment leak-protection demonstration, and a static-versus-server call behaviour that you can click through. Two components have already been developed: leak-check (to provide a visual indication of the client/server boundary) and mode-call (comparing static and server rendering side by side). There are six fixes, one adapter, one new page, and a bug resulting from two functions sharing a name rather too casually. Tomorrow: it will probably be more of the same.
Devlog #7: clean audits, fixed styling, faster boarding passes This round was about tightening things up. The dependency audit is finally clean with zero ignores. There are no more accepted-risk advisories in CI. Just real fixes: pinned overrides on esbuild and @hono /node-server, and moving shadcn out of production dependencies where it never belonged. I also fixed a frustrating Vercel bug where deployed pages lost their stylesheet. It turns out existsSync doesn’t work the way you’d expect inside a serverless bundle. Now, the CSS href gets included at build time instead of being guessed at runtime. Smaller wins: I swapped the landing page fonts to Space Grotesk, Inter, and JetBrains Mono (all self-hosted, no Google Fonts), fixed a boarding-pass demo bug where signed bit shifts were producing -6undefined seat numbers, and cleaned up lint/typecheck across the workspace. Repo (⭐ appreciated): https://github.com/abdelkabirouadoukou/x Website: https://thexjs.vercel.app/
Devlog #8 I redesigned the landing page. It is now black and white with no color at all. I reduced the boot animation from about 5.5 seconds to 4 seconds. CI now runs “bun run build” and a format check on every PR, not just typecheck, lint, and tests. I rewrote most of the docs to reflect reality. There are new pages for Islands, ISR, catch-all routes, batch server-function registration, and CLI flags. I fixed several issues that had occurred, including the wrong RouteProps type, bad apiDir docs, and incorrect 404/middleware behavior. Code blocks now use a monochrome token palette that matches the new design. I also fixed an actual bug. The rate limiter used a shared “unknown” bucket when proxy headers were missing. This meant one client’s burst could cause a 429 error for everyone else. Now it uses the correct socket IP first. I also corrected the missing content-type in the 429 response, which was causing issues with static assets in some browsers.
DevLog #9 I ran PageSpeed Insights on the x landing page and obtained the following results: 100 for performance, 100 for accessibility, 100 for best practices, 91 for SEO on desktop, and 96, 100, 100, and 91 on mobile. For a page that makes no use of any framework-level image optimization or lazy-loading techniquesinstead it’s just a monochrome static page built with Bun the SEO score of 91 is likely due to the fact that I haven’t yet added the meta tags; all the other aspects are clean. Built with x: https://github.com/abdelkabirouadoukou/x
Development Blog #10 I spent most of my time working on the documentation backlog of adding new features. The @thexjs /auth was released a blogs ago but I still had not done the documentation for it. We did not have a page for this and some old references were no longer working in other parts of the application. I made a page for /docs/packages/auth on the website. This page has instructions, information about the endpoints and details about CSRF. I also added links to this page from the data-layer and security pages so I do not have to repeat the information in many places. I also started working on the testing gaps that were on the roadmap and marked as “beta” or “not tested”. This includes things like what happens when Postgres is not working problems with authorization and limits for instances using Redis. I changed the way I work on changes. Of making all the changes in the main branch I now make a separate branch, for each change and then open a pull request. This is a way to do things so I will keep doing it this way.
Devlog #11 I found that browsers automatically remove tabs and newlines from a URL before checking its scheme, whereas my regex did not, and hence, I missed that javascript URLs could still bypass the sanitization and that is why they still worked. It ended up being part of releases 1.1.0 and 1.2.0. Also, I discovered that when checking whether environment leakage exists (build command is “x build”), this check silently fails without any message if environment is indeed leaky secrets get masked properly but “x build” exits with 0 and therefore CI never discovers that a feature has quietly malfunctioned. This time, the patches for both of these issues have been made properly and checked manually before merging. Roadmap backlog has been taken care of after that. The items are a real end-to-end RBAC example, Redis multi-replica soak test, which would stress the multi-db system in a very large-scale environment; and a time when the security disclosure SLA is truly acted out in real life scenario not just being a paper trail.
A loot of update i did plz check my repo to see them all [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!
I will update this post with all fixes and fetaures i did [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!
I will update this post with all fixes and fetaures i did [Update]: Just posted my last devlog, go read that for the full details! Worked on the @thexjs /mcp server (so that AI agents won’t make up incorrect code for x), some documentation cleanup, some landing page hero/sidebar improvements, and a few adapter/scaffolder bug fixes. Repo links are included if you want to see the real code changes!
This post will be updated soon..
Devlog #12 this cycle was about mostly about closing the loop from “framework that works” to “framework someone else can actually adopt without me hovering nearby” Most importantly, agents can now understand x every dev I know, including senior devs, is now asking AI to write code for them. AI doesn’t know x conventions and will confidently write next.js or remix code that looks right but isn’t. So I released @thexjs /mcp - an MCP server for claude code, cursor and other agents that gives them concrete documentation for routing, loaders, server functions, env vars, and a scaffold_file tool that generates files in the right shape rather than the agent making up whatever it wants. This gets automatically added to any new project via .mcp.json / .cursor/mcp.json, and there’s also an llms.txt file on the docs for agents that just browse the site. They’re both generated from the same source so they can’t diverge. The docs got a much needed love, not just in terms of content I added the missing @thexjs /mcp docs page, and got it linked into the sidebar/footer/search index (it was in the code but not easy to find). I also fixed some copy that had diverged from the actual implementation, including a docs page that suggested using “use client” directives that the framework doesn’t actually support. The landing page also got some updates The hero section is now properly responsive (it broke on real phones, not just narrow desktops). There was a bug where the docs sidebar was supposed to be sticky but wasn’t - fixed that (turns out it was an ancestor issue, not the sticky style itself). Copy was de-genericized a bit, since it was previously very similar to other dev tool landing pages. Some internal improvements I fixed a bug in the vercel adapter relating to forwarded-header hostname validation, and made some improvements to the scaffolder (shadcn wasn’t being installed when tailwind was automatically enabled, doctor’s semver range checks were actually checking the ranges, etc). I’m now using proper feature branches + PRs for everything rather than pushing to main directly. It’s more work but should avoid situations where, say, the docs get updated to disagree with the framework in confusing ways. If you want more details on any of this, check my repo!!
Devlog #13 Fixed two critical auth bugs, both related to the auth package; the fixes are already in the PRs (not merged yet, waiting for CI). sqlite session store silently overwritten created_at (#175) Postgres store used ON CONFLICT (token) DO UPDATE, which does not update created_at column on purpose; therefore, on each re-login with the same token, the created_at would remain the same, signifying that the session was created at the same time. However, the sqlite had a different approach of INSERT OR REPLACE which replaced the whole row, including created_at. This PR changes the sqlite version to use the explicit upsert so that both databases behave the same way. Also adds a regression test that purposely creates a session, re-logins with the same token/data and checks that created_at was not changed. The postgres tests are skipped for local DATABASE_URL absent. AuthGuardResult lied on success (#177) AuthGuardResult was a type { ok: boolean; status: 401 | 403; reason: string }, and on success, the guard returned { ok: true, status: 401, reason: “” }, i.e., a 401 status code with an empty reason string. It was not a problem because toMiddleware always checked result.ok first, but it was a silent bug for anyone who tried to check result.status on success. Now it is properly represented as a discriminated union type { ok: true } | { ok: false; status: 401 | 403; reason: string }, and the status and reason fields are not present on success. All tests were adjusted to narrow the type with if (!result.ok) { … }, and a new test checks that TypeScript actually narrows the type.
I will update this post soon..
Ships:
Built “X” — a lightweight full-stack React framework powered natively by the Bun runtime. In this update, I focused on getting the core Server-Side Rendering (SSR) pipeline smooth and ultra-fast. I refactored the dev server to make hot-reloading seamless, fixed routing edge cases, and polished the CLI so you can spin up a full-stack React app with zero-config overhead. The goal is to keep modern React development fast, simple, and bloat-free by leveraging Bun’s speed.
Ship #2 is finally done after 50+ hours. Shipped build-time secret leak protection, Vercel deployments, structured logging, and a 100/100 PageSpeed landing page redesign. Check the repo for all the devlogs!
Ship #3 - X is pre-production ready X is a full-stack React framework written natively in Bun. It has seen 90+h development and is at the point where I can hand it over to someone else and walk away. What’s in the box • File-based routing with SSR, SSG, ISR - pick per route • Islands architecture for client interactivity, no more use client • Server functions, which at build-time are rewritten to fetch wrappers • Authentication package with credentials + OAuth2, sessions, CSRF, brute-force protection, RBAC • Build-time environment leakage check, implemented as an AST visitor that fails the build on a secret accidental exposure • Adapter for Vercel that generates a .vercel/output directory with static CDN and serverless SSR • MCP server for training AI agents that write correct x applications, not hallucinating Next.js code • Structured JSON logs, /healthz, /readyz, OpenTelemetry/Sentry hooks • Docker builds with explicit workspace COPY gates and CVE scanning at build-time What’s been fixed in this cycle: • SQLite session store did not observe created_at on relogin, unlike Postgres • The AuthGuardResult object had { ok: ‘success’, status: 401 } shape on successful auth guard resolution, has been renamed to a discriminated union type to avoid carrying stale data • The Vercel adapter accepted comma-joined X-Forwarded-For headers that should have been rejected • The auth package had code duplication between brute-force protection and audit logging for parsing X-Forwarded-For, consolidated into a clientIpFromRequest util • The hero component on the landing page broke on actual mobile viewports - fixed a responsive slab assumption in the install command component • Docs had foreign framework artifacts (use client directives, wrong loader signatures), all scrubbed CI is properly set up now, only merged branches push changes. For every PR: • TypeScript checks, Biome linting, tests run on Ubuntu/macOS • Postgres migration checks, Docker builds with CVE scans • Package audits (using a sha256-pinned manifest), load-testing with SLOs • Vercel preview deploys, changeset validation for monorepo packages No automatic merging - everything is watched by the repo until the CI turns green and the PR is squashed. Repo: https://github.com/abdelkabirouadoukou/x Docs: https://thexjs.abdelkabir.me/...
|
1792986959.6449192
|
1793073359.6449192
|
|
20008
|
SpaceGuessr by @Jaron | Stardance
|
Jaron
|
3
|
99.0
|
1811
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-19T18:20:49Z", "hours": 39.0, "multiplier": 19.83, "payout": 780, "blessing": "neutral", "text": "SpaceGuessr is a small browser game where you have to guess real space objects from NASA images. It works kinda like GeoGuessr, but instead of places on Earth you get planets, moons, nebulae, galaxies and other space stuff. The game has different modes like Classic, Timed, Blind Reveal, Learn and Reverse Learn, so you can either play for score or just practice. Technically the project is built with plain HTML, CSS and JavaScript, without any big framework. index.html contains the screens and buttons, style.css handles the layout, animations and responsive design, and script.js contains the main game logic like loading questions, checking answers, calculating score, streaks, timers, hints, leaderboards and local profile stats. The questions are stored in game-data.js, while mode settings like rounds, hints and timers are stored in game-config.js. The game also uses localStorage to save local stats, recent runs and fallback scores in the browser. For online scores it can use Supabase, but if that does not work the game still runs normally. Overall, SpaceGuessr is a space guessing game made with simple web technologys, real NASA images and a few extra features.", "repo": "https://github.com/Blizz606/SpaceGuessr", "demo": "https://blizz606.github.io/SpaceGuessr"}, {"ship_num": 2, "ts": "2026-07-05T20:02:26Z", "hours": 58.0, "multiplier": 17.26, "payout": 1009, "blessing": "neutral", "text": "SpaceGuessr is basically my version of “GeoGuessr, but in space” — a browser game where you guess planets, moons, nebulae, galaxies, and other space objects from real NASA-based images. At first, I thought this would just be a simple guessing game, but it quickly turned into a much bigger project. I kept adding more modes, more polish, better UI, scoring, animations, and content until it started to feel like an actual game instead of just a small prototype. Right now, SpaceGuessr has multiple game modes like Quick, Classic, Timed, Daily, Infinite, and Blind Reveal. Blind Reveal is one of my favorite parts: the image slowly uncovers itself while your possible score drops over time, so you have to decide whether to guess early or wait for more information. I also added a full scoring system with streak bonuses, animated feedback, end screens, keyboard controls, responsive design, leaderboard support, local fallback saving, confetti, reveal effects, round transitions, and a lot of small game-feel details. I spent a lot of time on these small things because they make the game feel much more satisfying to play. A big part of the work was also the content. The game uses a curated pool of 70+ NASA-based images, with correct answers, wrong answers, facts, and difficulty balancing. I kept improving the image pool so the game doesn’t feel repetitive, and I added logic so the same image won’t repeat during one run. Technically, the whole project is built with plain HTML, CSS, and JavaScript, without using a big framework. That meant a lot of the animations, UI states, game logic, scoring, and mode handling had to be built manually. I also added Supabase for global leaderboards and deployed everything with GitHub Pages so anyone can just open it and play instantly. I’m really proud of SpaceGuessr because it started as a simple idea and became one of my most complete projects so far. It’s playable, replayable, polished, and actually fun to come back to. I put a lot of time into making it feel smooth, finished, and cared for — and I think that shows in the final game. Thanks to everyone who is supporting this project <3", "repo": "https://github.com/Blizz606/SpaceGuessr", "demo": "https://blizz606.github.io/SpaceGuessr"}, {"ship_num": 3, "ts": "2026-06-16T17:53:36Z", "hours": 2.0, "multiplier": 9.65, "payout": 22, "blessing": "neutral", "text": "SpaceGuessr is like GeoGuessr, but in space. Explore planets, galaxies, nebulae, and more using real images provided by the NASA API. Guess where each image was taken or what it shows, compete for high scores, and climb the global leaderboard powered by Supabase.", "repo": "https://github.com/Blizz606/SpaceGuessr", "demo": "https://blizz606.github.io/SpaceGuessr"}]...
|
[{"post_id": 31367, "ts": "202 [{"post_id": 31367, "ts": "2026-07-19T18:08:17Z", "hours": 3.8328, "text": "Devlog #1.7 I added the recent Runs to the Profile Menu and redesigned it, because it didn’t looked special. I think it has a smooth animation now. When there are bugs it would be cool if you could tell me. <3"}, {"post_id": 30775, "ts": "2026-07-18T17:23:00Z", "hours": 4.1169, "text": "Devlog #1.6 Today I added a small profile in the right bottom. You can see your best scores and more. Everything is safed in localStorage, so no Account or smth. like that is needed.- I had to find an elegant way to save all the stats in localStorage, but I think it turned out well. I will have more time in the following days cause summer break started yesterday."}, {"post_id": 30577, "ts": "2026-07-18T08:37:38Z", "hours": 1.7933, "text": "Devlog #1.5 Added a small local best score system to the main menu. It now checks saved leaderboard data in localStorage and shows the best score for the currently selected mode in a subtle way under the mode description. I also made sure it updates automatically when switching modes and after saving a run, while Daily , Learn , and Reverse Learn show a muted status message instead of a score because they are not normal saved score modes."}, {"post_id": 30173, "ts": "2026-07-17T15:16:05Z", "hours": 9.9933, "text": "Devlog #1.4 Today I worked more on polishing SpaceGuessr and making the special modes feel better. The biggest change was adding Reverse Learn , it’s a mode where the clue shows up in the middle of the screen first and then you have to guess the answer. I also improved the popup for missed images, polished some UI details like panels, spacing, and animations, and updated the README so it matches the current version better. Overall the game just feels cleaner and more finished now. And fun fact: I hit the stardance limit with this change, I saw just now that I could only commit 10h max. But I squeezed everything into the 10h. I will fix some stuff later like the loading times of the modes."}, {"post_id": 28442, "ts": "2026-07-14T18:05:48Z", "hours": 5.1764, "text": "Devlog #1.3 Today I polished the game UI again and cleaned up some smaller details. I improved the help menu, made the top progress bar more visible, and changed the end screen so the leaderboard does not show up immediately. I also adjusted the main menu layout a little so the background has more space and the screen feels cleaner. Nothing huge today, but the game feels nicer and more polished now. The Help Button is a bit weird but I will fix it later."}, {"post_id": 27151, "ts": "2026-07-12T13:29:59Z", "hours": 7.6275, "text": "Devlog #1.2 Today I expanded SpaceGuessr with selectable learn packs and improved the learning flow. I also added a much larger centralized content file with many new space questions, plus UI updates like new backgrounds, smoother image loading, and an end-of-session review for learn mode. The project now feels more polished, more scalable, and better suited for replayability. Main Goal was just making the code easier to understand and implementing the Feedback. You can try it now . I would love to here some more feedback. <3"}, {"post_id": 26735, "ts": "2026-07-11T18:14:20Z", "hours": 6.7786, "text": "Devlog #1.1 In the last GitHub commit, I cleaned up the game structure. I added Learn Mode , moved the mode settings into game-config.js , and moved the space questions into game-data.js . I also improved some animations, mobile styling, and Blind Reveal. In the newest commit, I updated the main menu with Casual and Special sections. Special mode now has a smooth background change with the new image (The Image is generated by AI). I also updated the README and added a few small CSS improvements. PS: Thanks to all of u. My last Ship was rated awesome. Thanks to everybody who played it and especially rated it. <3"}, {"post_id": 23047, "ts": "2026-07-05T19:38:41Z", "hours": 6.6544, "text": "Devlog #21 This is a kinda long devlog so thanks to everyone who is really reding it all the way. This update was a bigger gameplay and polish pass focused on turning SpaceGuessr into a more complete and shippable version. New game mode and scoring changes Replaced the old Infinite mode with a new Blind Reveal mode because it’s more fun Added countdown support for Blind Reveal Reworked scoring so Blind Reveal starts at higher points and drops with each reveal step Added streak bonus scoring, so longer streaks now reward extra points Updated leaderboard handling so score-chasing modes save automatically after a run Gameplay and UX improvements Added confetti for correct answers (discourse.webflow.com) Added a stronger streak animation when a streak continues Added danger styling for the countdown when time is low (red) Improved answer feedback presentation and round transition Added subtle round motion polish plus small audio cues for hints, correct answers, wrong answers, streaks, and end-of-run results Menu and endscreen polish Added a help button in the main menu that opens a smooth animated help panel Added scoring explanations directly into the help panel Removed the visible dark/light mode toggle and kept the game in the default light theme Reworked the endscreen so score saving is more compact Removed the large manual “save your best run” panel and switched to automatic score saving when possible Added a run summary/final run text on the endscreen so the result feels more personal and less like raw stats only Cleaned up feedback so success toasts are gone and only errors appear as top toasts Leaderboard and save flow Added local-first score saving with global leaderboard sync afterward Improved fallback behavior when global leaderboard writes fail Simplified the save-name experience so the player is only asked for a leaderboard name when needed Improved leaderboard modal behavior in the menu Content expansion Added 30 new NASA image entries to the question pool ChatGPT helped research and pick these new images from the official NASA Image and Video Library Added matching answer sets, facts, and difficulty tags for the new entries New content includes objects and scenes like: Venus Io Deimos Mimas Tethys Hyperion Oberon Umbriel Titania Sun Helix Nebula Carina Nebula Trifid Nebula Flame Nebula Butterfly Nebula Triangulum Galaxy Pinwheel Galaxy Cartwheel Galaxy Centaurus A Sculptor Galaxy Antennae Galaxies M81 Galaxy M82 Galaxy Stephan Quintet Pillars of Creation Charon Nix Hydra Phoebe Olympus Mons Current state At this point the project feels much more release-ready than before, with the biggest remaining work being final balancing, QA across all modes, and a last pass on leaderboard edge cases."}, {"post_id": 22681, "ts": "2026-07-05T07:30:11Z", "hours": 6.2978, "text": "Devlog #20 This DL was mostly about cleaning up and tightening the project without changing its core. A big part of the work went into reorganizing the css so it is much easier to maintain. I also moved more of the repeated colors, borders, and shadow values into variables, which makes the system feel more consistent. On top of that, button states and status states were cleaned up so things like hover, disabled, correct, and wrong feel more unified across the game. The mobile version also got a proper polish pass while keeping the desktop version untouched. The start screen was tightened up so it uses space better, the logo and card proportions feel more balanced, and the Daily Mode button sits more naturally in the layout. Besides that, there was some general UI polish throughout the game. Answer feedback feels more intentional now, the HUD relies more on shared styling tokens, and the whole thing is internally a lot cleaner even though the overall look stays very close to what it was before. Thanks for the support from all of U"}, {"post_id": 20982, "ts": "2026-07-02T18:37:45Z", "hours": 2.1589, "text": "Devlog #19 UI polish and bug fixes I Improved the mobile flow by replacing the mode button row with a dropdown and simplifying the mobile start screen. Extended the round progress animation so it stays visible longer and can continue while the next image is already shown. Added small no-sound interaction feedback such as answer animations, panel flashes, and a ready pulse on the next button. Fixed stale feedback content so old round text does not linger after moving to the next round. Polished the dark mode with better contrast, deeper panel styling, and more consistent button states."}, {"post_id": 20107, "ts": "2026-07-01T17:07:17Z", "hours": 3.2425, "text": "Devlog #18 SpaceGuessr started with a simple idea: GeoGuessr, but in space. Instead of streets and cities, players guess real NASA images showing planets, moons, nebulae, and galaxies. The game is now fully playable with modes like Quick , Classic , Timed , Daily , and Infinite , plus score tracking, facts after rounds, a polished responsive UI, and leaderboard features. The feedback so far has been very positive. People like the concept, the visual style, and the replay value. The biggest next steps are making the game more educational and more competitive. Next, I want to improve: a Learn Mode or better info/fact screens stronger leaderboard and competition features better feedback for low or negative scores more mobile polish better devlogs and project storytelling I am really happy with the current state. The core idea works, and now the goal is to make it deeper, smarter, and even more replayable. PS: It’s awesome that I got so much good feedback, so I can improve SpaceGuessr. Thanks to all of u (:"}, {"post_id": 19375, "ts": "2026-06-30T17:43:59Z", "hours": 2.7389, "text": "Devlog #17 Today I polished the SpaceGuessr UI a lot and also cleaned up how small animation states work in the game. What I improved Reworked the start menu so the main card feels bigger and more like a real game menu Made the game mode area clearer with better spacing and stronger visual focus Updated the mode descriptions so they sound cleaner and more professional Made the start button larger and more important visually Removed the small line/gloss artifact from the selected game mode tab Improved the dark mode styling so the in-game UI feels less weird and more consistent Reworked the final report card so it matches the rest of the project style better Cleaned up the light mode end screen because it looked too washed out before Improved the theme toggle so it fits the glass / space design better JS improvements I also added small UI animation states in JavaScript instead of only relying on random class toggles. New state classes now include things like: is-transitioning is-answering is-feedback-open is-round-complete is-results-view That makes the UI feel more stable and gives smoother transitions between: loading a round answering opening feedback showing the end screen Small code example function setUiState ( stateKey , isActive ) { const stateClassName = uiStateClassMap [ stateKey ]; if ( ! stateClassName ) { return ; } uiStateTargets . forEach (( element ) => { element . classList . toggle ( stateClassName , isActive ); }); }"}, {"post_id": 18580, "ts": "2026-06-29T19:29:38Z", "hours": 1.7408, "text": "Devlog #16 Today I cleaned up the HTML structure of SpaceGuessr to make it easier to understand and closer to how I would actually explain the project. I cleaned up a few small text details in the HTML, fixed some weird special characters, and made the structure more readable overall. Also I revamped some of the In-Game UI. The functionality stayed the same, but the file is now much easier to follow."}, {"post_id": 17823, "ts": "2026-06-28T19:14:39Z", "hours": 4.6086, "text": "Devlog #15 Today I focused on polishing the visual consistency of SpaceGuessr. I cleaned up the theme system in the CSS by introducing more shared variables for light mode, dark mode, navigation elements, and the theme toggle. I also unified several animation timings so that screen transitions, menu interactions, answer cards, and UI panels feel more consistent. After that, I reworked the end screen so it matches the rest of the interface better. The result card, stat tiles, leaderboard section, and share popup now use the same general visual language as the menu and in-game UI. I also updated the end screen to use the same background image as the main menu, which makes the whole app feel more connected. I wasn’t able to do so much the past days, because here in germany it’s like 40 degree Celsius."}, {"post_id": 16797, "ts": "2026-06-27T08:40:37Z", "hours": 1.66, "text": "Devlog #14 I refined the main menu of SpaceGuessr to make the game mode selection feel cleaner and more polished. I reworked the central menu card so it looks larger, more focused, and closer to a real browser game menu. I also improved the visual hierarchy by giving the mode area a clearer title and better spacing between the mode tabs, the description, and the start button. Also, I polished the game mode tabs themselves. The active tab is now more clearly highlighted, while the inactive tabs are slightly toned down so the selected mode stands out better without making the UI feel too busy."}, {"post_id": 15833, "ts": "2026-06-25T19:02:15Z", "hours": 1.3828, "text": "Devlog #13 Today I added two small but useful gameplay improvements to SpaceGuessr. First, I removed hints from Daily Mode. The daily challenge is now a bit fairer because every player gets the same image without extra help. I handled this directly in the JavaScript by setting Daily Mode hints to 0 , hiding the hint UI in that mode, and blocking the hint function there as a backup. Second, I added keyboard controls for smoother gameplay. You can now press 1 , 2 , 3 , or 4 to choose an answer and use Enter to continue to the next round after answering. I hand’t much time the previous days, so I’m glad I could improve something today."}, {"post_id": 13741, "ts": "2026-06-22T15:06:42Z", "hours": 3.1017, "text": "Devlog #12 (UI-Redeign) Today I spent a good amount of time polishing the actual game UI so it feels more like a real browser game instead of a random prototype screen on top of an image. The biggest change was the in-game layout. I reworked the top navigation so it feels cleaner and more structured, with Home , Round , Streak , Time , and Score behaving more like proper game UI elements. I also kept improving the answer area at the bottom, so the feedback card, answer buttons, and action button feel more connected and easier to read. Another bigger feature was the new dark/light mode toggle in the bottom-right corner. It now actually changes the game UI theme and stores the selected mode in localStorage , so the theme stays the same after reloading the page. Theme Toggle Example function applyGameTheme ( themeName ) { const isDarkTheme = themeName === \" dark \" ; document . body . classList . toggle ( \" game-ui-dark \" , isDarkTheme ); localStorage . setItem ( gameThemeStorageKey , isDarkTheme ? \" dark \" : \" light \" ); } I will redesign the Summary Page as fast as I can. Today was really productive actually, only thing I had problems with, is some of the CSS and especially some of the animations, so I used some AI there."}, {"post_id": 13249, "ts": "2026-06-21T18:10:20Z", "hours": 1.7842, "text": "Devlog #11 Today I cleaned up the main menu UI to make it feel calmer and more polished. I moved the Daily Mode button out from inside the main panel and placed it below as its own extra action, which makes the menu structure easier to understand. Also I redesigned the Logo to catch the vibe more. Today was my most productive day with crazy 8h tracked, since it was weekend here in Germany. I’m long not done with the project, I have so many things that I want to add."}, {"post_id": 13104, "ts": "2026-06-21T13:15:53Z", "hours": 2.5442, "text": "Devlog #10 Worked on the final mission report screen and the share popup polish. I improved the result screen spacing, pushed the score section lower for a cleaner layout, and added clearer stat colors so correct answers stand out in green and wrong answers in red. I also added the share popup to the main end-screen. Copy function in the Share Pop-Up const shareText = getShareText(); try { await navigator.clipboard.writeText(shareText); clearTimeout(copyButtonResetTimer); copyShareButton.classList.add(\"copied\"); copyButtonResetTimer = setTimeout(() => { copyShareButton.classList.remove(\"copied\"); }, 1200); } catch {} } Try it now"}, {"post_id": 13020, "ts": "2026-06-21T09:16:53Z", "hours": 1.805, "text": "Devlog #9 I reworked the hint system in SpaceGuessr and improved how it fits into the gameplay. The hint feature is now more compact in the UI and is designed to feel like a natural part of the round instead of a separate text block."}, {"post_id": 12983, "ts": "2026-06-21T07:24:04Z", "hours": 3.2494, "text": "Devlog #8 Today I improved the overall game flow and polished some things. I added a hint system with different hint counts depending on the game mode, refined the answer feedback timing, and cleaned up the spacing in the in-game detail panel. I also shortened the fact text for the space images."}, {"post_id": 12607, "ts": "2026-06-20T16:24:35Z", "hours": 1.5767, "text": "Devlog #7 Try it now Today I refined the answer flow in SpaceGuessr to make each guess feel smoother and more deliberate. I adjusted the feedback timing, improved the reveal flow after selecting an answer, and gave the feedback area better spacing so the UI feels cleaner. I also shortened the fact text for each space image so the information is easier to scan and fits the layout more consistently without feeling overcrowded."}, {"post_id": 12433, "ts": "2026-06-20T09:10:03Z", "hours": 4.4494, "text": "Devlog #6 Today I kept improving SpaceGuessr as a small playable web game and focused mostly on polish, flow, and presentation. I added a streak system, refined the end screen, improved the loading and background preloading behavior and more so it feels smoother and more complete. I also reworked the help section in the main menu, simplified parts of the HTML structure, and cleaned up the overall interface so the project feels more understandable and closer to a finished mini product. I had some problems with the Streak system, but AI helped me solve it quickly."}, {"post_id": 12106, "ts": "2026-06-19T19:28:24Z", "hours": 1.5339, "text": "Built a new help panel for SpaceGuessr today. There’s now a small ? button in the main menu that opens a smooth in-game guide with mode explanations and a direct link to the GitHub docs. Small feature, but it makes the whole project feel a lot more polished and beginner-friendly."}, {"post_id": 12049, "ts": "2026-06-19T17:29:09Z", "hours": 3.5011, "text": "Devlog #4 I just added a new Daily Mode to the game and connected it with Supabase . Try it now You can now guess one image per day and compete with others through the daily challenge. I had some problems while integrating the feature, so I used ChatGPT a bit for debugging. In the end, the error was actually pretty obvious, but that’s just how debugging goes sometimes I guess."}, {"post_id": 11507, "ts": "2026-06-18T20:00:20Z", "hours": 4.0894, "text": "Devlog #3 I just recoded a major part of the game and finally fixed some important bugs in Infinite Mode. Hopefully everything is working smoothly now. Stay tuned for future updates on SpaceGuesrr !"}, {"post_id": 10129, "ts": "2026-06-16T18:48:28Z", "hours": 0.3333, "text": "Just revamped the scoring system"}, {"post_id": 10075, "ts": "2026-06-16T17:34:26Z", "hours": 1.9494, "text": "GeoGuesser just in Space (v1.0)"}, {"post_id": 9991, "ts": "2026-06-16T15:00:48Z", "hours": 0.3003, "text": "Currently working on SpaceGuessr"}]...
|
Title: SpaceGuessr by @Jaron | Stardance
Devlogs: Title: SpaceGuessr by @Jaron | Stardance
Devlogs:
Currently working on SpaceGuessr
GeoGuesser just in Space (v1.0)
Just revamped the scoring system
Devlog #3 I just recoded a major part of the game and finally fixed some important bugs in Infinite Mode. Hopefully everything is working smoothly now. Stay tuned for future updates on SpaceGuesrr !
Devlog #4 I just added a new Daily Mode to the game and connected it with Supabase . Try it now You can now guess one image per day and compete with others through the daily challenge. I had some problems while integrating the feature, so I used ChatGPT a bit for debugging. In the end, the error was actually pretty obvious, but that’s just how debugging goes sometimes I guess.
Built a new help panel for SpaceGuessr today. There’s now a small ? button in the main menu that opens a smooth in-game guide with mode explanations and a direct link to the GitHub docs. Small feature, but it makes the whole project feel a lot more polished and beginner-friendly.
Devlog #6 Today I kept improving SpaceGuessr as a small playable web game and focused mostly on polish, flow, and presentation. I added a streak system, refined the end screen, improved the loading and background preloading behavior and more so it feels smoother and more complete. I also reworked the help section in the main menu, simplified parts of the HTML structure, and cleaned up the overall interface so the project feels more understandable and closer to a finished mini product. I had some problems with the Streak system, but AI helped me solve it quickly.
Devlog #7 Try it now Today I refined the answer flow in SpaceGuessr to make each guess feel smoother and more deliberate. I adjusted the feedback timing, improved the reveal flow after selecting an answer, and gave the feedback area better spacing so the UI feels cleaner. I also shortened the fact text for each space image so the information is easier to scan and fits the layout more consistently without feeling overcrowded.
Devlog #8 Today I improved the overall game flow and polished some things. I added a hint system with different hint counts depending on the game mode, refined the answer feedback timing, and cleaned up the spacing in the in-game detail panel. I also shortened the fact text for the space images.
Devlog #9 I reworked the hint system in SpaceGuessr and improved how it fits into the gameplay. The hint feature is now more compact in the UI and is designed to feel like a natural part of the round instead of a separate text block.
Devlog #10 Worked on the final mission report screen and the share popup polish. I improved the result screen spacing, pushed the score section lower for a cleaner layout, and added clearer stat colors so correct answers stand out in green and wrong answers in red. I also added the share popup to the main end-screen. Copy function in the Share Pop-Up const shareText = getShareText(); try { await navigator.clipboard.writeText(shareText); clearTimeout(copyButtonResetTimer); copyShareButton.classList.add("copied"); copyButtonResetTimer = setTimeout(() => { copyShareButton.classList.remove("copied"); }, 1200); } catch {} } Try it now
Devlog #11 Today I cleaned up the main menu UI to make it feel calmer and more polished. I moved the Daily Mode button out from inside the main panel and placed it below as its own extra action, which makes the menu structure easier to understand. Also I redesigned the Logo to catch the vibe more. Today was my most productive day with crazy 8h tracked, since it was weekend here in Germany. I’m long not done with the project, I have so many things that I want to add.
Devlog #12 (UI-Redeign) Today I spent a good amount of time polishing the actual game UI so it feels more like a real browser game instead of a random prototype screen on top of an image. The biggest change was the in-game layout. I reworked the top navigation so it feels cleaner and more structured, with Home , Round , Streak , Time , and Score behaving more like proper game UI elements. I also kept improving the answer area at the bottom, so the feedback card, answer buttons, and action button feel more connected and easier to read. Another bigger feature was the new dark/light mode toggle in the bottom-right corner. It now actually changes the game UI theme and stores the selected mode in localStorage , so the theme stays the same after reloading the page. Theme Toggle Example function applyGameTheme ( themeName ) { const isDarkTheme = themeName === " dark " ; document . body . classList . toggle ( " game-ui-dark " , isDarkTheme ); localStorage . setItem ( gameThemeStorageKey , isDarkTheme ? " dark " : " light " ); } I will redesign the Summary Page as fast as I can. Today was really productive actually, only thing I had problems with, is some of the CSS and especially some of the animations, so I used some AI there.
Devlog #13 Today I added two small but useful gameplay improvements to SpaceGuessr. First, I removed hints from Daily Mode. The daily challenge is now a bit fairer because every player gets the same image without extra help. I handled this directly in the JavaScript by setting Daily Mode hints to 0 , hiding the hint UI in that mode, and blocking the hint function there as a backup. Second, I added keyboard controls for smoother gameplay. You can now press 1 , 2 , 3 , or 4 to choose an answer and use Enter to continue to the next round after answering. I hand’t much time the previous days, so I’m glad I could improve something today.
Devlog #14 I refined the main menu of SpaceGuessr to make the game mode selection feel cleaner and more polished. I reworked the central menu card so it looks larger, more focused, and closer to a real browser game menu. I also improved the visual hierarchy by giving the mode area a clearer title and better spacing between the mode tabs, the description, and the start button. Also, I polished the game mode tabs themselves. The active tab is now more clearly highlighted, while the inactive tabs are slightly toned down so the selected mode stands out better without making the UI feel too busy.
Devlog #15 Today I focused on polishing the visual consistency of SpaceGuessr. I cleaned up the theme system in the CSS by introducing more shared variables for light mode, dark mode, navigation elements, and the theme toggle. I also unified several animation timings so that screen transitions, menu interactions, answer cards, and UI panels feel more consistent. After that, I reworked the end screen so it matches the rest of the interface better. The result card, stat tiles, leaderboard section, and share popup now use the same general visual language as the menu and in-game UI. I also updated the end screen to use the same background image as the main menu, which makes the whole app feel more connected. I wasn’t able to do so much the past days, because here in germany it’s like 40 degree Celsius.
Devlog #16 Today I cleaned up the HTML structure of SpaceGuessr to make it easier to understand and closer to how I would actually explain the project. I cleaned up a few small text details in the HTML, fixed some weird special characters, and made the structure more readable overall. Also I revamped some of the In-Game UI. The functionality stayed the same, but the file is now much easier to follow.
Devlog #17 Today I polished the SpaceGuessr UI a lot and also cleaned up how small animation states work in the game. What I improved Reworked the start menu so the main card feels bigger and more like a real game menu Made the game mode area clearer with better spacing and stronger visual focus Updated the mode descriptions so they sound cleaner and more professional Made the start button larger and more important visually Removed the small line/gloss artifact from the selected game mode tab Improved the dark mode styling so the in-game UI feels less weird and more consistent Reworked the final report card so it matches the rest of the project style better Cleaned up the light mode end screen because it looked too washed out before Improved the theme toggle so it fits the glass / space design better JS improvements I also added small UI animation states in JavaScript instead of only relying on random class toggles. New state classes now include things like: is-transitioning is-answering is-feedback-open is-round-complete is-results-view That makes the UI feel more stable and gives smoother transitions between: loading a round answering opening feedback showing the end screen Small code example function setUiState ( stateKey , isActive ) { const stateClassName = uiStateClassMap [ stateKey ]; if ( ! stateClassName ) { return ; } uiStateTargets . forEach (( element ) => { element . classList . toggle ( stateClassName , isActive ); }); }
Devlog #18 SpaceGuessr started with a simple idea: GeoGuessr, but in space. Instead of streets and cities, players guess real NASA images showing planets, moons, nebulae, and galaxies. The game is now fully playable with modes like Quick , Classic , Timed , Daily , and Infinite , plus score tracking, facts after rounds, a polished responsive UI, and leaderboard features. The feedback so far has been very positive. People like the concept, the visual style, and the replay value. The biggest next steps are making the game more educational and more competitive. Next, I want to improve: a Learn Mode or better info/fact screens stronger leaderboard and competition features better feedback for low or negative scores more mobile polish better devlogs and project storytelling I am really happy with the current state. The core idea works, and now the goal is to make it deeper, smarter, and even more replayable. PS: It’s awesome that I got so much good feedback, so I can improve SpaceGuessr. Thanks to all of u (:
Devlog #19 UI polish and bug fixes I Improved the mobile flow by replacing the mode button row with a dropdown and simplifying the mobile start screen. Extended the round progress animation so it stays visible longer and can continue while the next image is already shown. Added small no-sound interaction feedback such as answer animations, panel flashes, and a ready pulse on the next button. Fixed stale feedback content so old round text does not linger after moving to the next round. Polished the dark mode with better contrast, deeper panel styling, and more consistent button states.
Devlog #20 This DL was mostly about cleaning up and tightening the project without changing its core. A big part of the work went into reorganizing the css so it is much easier to maintain. I also moved more of the repeated colors, borders, and shadow values into variables, which makes the system feel more consistent. On top of that, button states and status states were cleaned up so things like hover, disabled, correct, and wrong feel more unified across the game. The mobile version also got a proper polish pass while keeping the desktop version untouched. The start screen was tightened up so it uses space better, the logo and card proportions feel more balanced, and the Daily Mode button sits more naturally in the layout. Besides that, there was some general UI polish throughout the game. Answer feedback feels more intentional now, the HUD relies more on shared styling tokens, and the whole thing is internally a lot cleaner even though the overall look stays very close to what it was before. Thanks for the support from all of U
Devlog #21 This is a kinda long devlog so thanks to everyone who is really reding it all the way. This update was a bigger gameplay and polish pass focused on turning SpaceGuessr into a more complete and shippable version. New game mode and scoring changes Replaced the old Infinite mode with a new Blind Reveal mode because it’s more fun Added countdown support for Blind Reveal Reworked scoring so Blind Reveal starts at higher points and drops with each reveal step Added streak bonus scoring, so longer streaks now reward extra points Updated leaderboard handling so score-chasing modes save automatically after a run Gameplay and UX improvements Added confetti for correct answers (discourse.webflow.com) Added a stronger streak animation when a streak continues Added danger styling for the countdown when time is low (red) Improved answer feedback presentation and round transition Added subtle round motion polish plus small audio cues for hints, correct answers, wrong answers, streaks, and end-of-run results Menu and endscreen polish Added a help button in the main menu that opens a smooth animated help panel Added scoring explanations directly into the help panel Removed the visible dark/light mode toggle and kept the game in the default light theme Reworked the endscreen so score saving is more compact Removed the large manual “save your best run” panel and switched to automatic score saving when possible Added a run summary/final run text on the endscreen so the result feels more personal and less like raw stats only Cleaned up feedback so success toasts are gone and only errors appear as top toasts Leaderboard and save flow Added local-first score saving with global leaderboard sync afterward Improved fallback behavior when global leaderboard writes fail Simplified the save-name experience so the player is only asked for a leaderboard name when needed Improved leaderboard modal behavior in the menu Content expansion Added 30 new NASA image entries to the question pool ChatGPT helped research and pick these new images from the official NASA Image and Video Library Added matching answer sets, facts, and difficulty tags for the new entries New content includes objects and scenes like: Venus Io Deimos Mimas Tethys Hyperion Oberon Umbriel Titania Sun Helix Nebula Carina Nebula Trifid Nebula Flame Nebula Butterfly Nebula Triangulum Galaxy Pinwheel Galaxy Cartwheel Galaxy Centaurus A Sculptor Galaxy Antennae Galaxies M81 Galaxy M82 Galaxy Stephan Quintet Pillars of Creation Charon Nix Hydra Phoebe Olympus Mons Current state At this point the project feels much more release-ready than before, with the biggest remaining work being final balancing, QA across all modes, and a last pass on leaderboard edge cases.
Devlog #1.1 In the last GitHub commit, I cleaned up the game structure. I added Learn Mode , moved the mode settings into game-config.js , and moved the space questions into game-data.js . I also improved some animations, mobile styling, and Blind Reveal. In the newest commit, I updated the main menu with Casual and Special sections. Special mode now has a smooth background change with the new image (The Image is generated by AI). I also updated the README and added a few small CSS improvements. PS: Thanks to all of u. My last Ship was rated awesome. Thanks to everybody who played it and especially rated it. <3
Devlog #1.2 Today I expanded SpaceGuessr with selectable learn packs and improved the learning flow. I also added a much larger centralized content file with many new space questions, plus UI updates like new backgrounds, smoother image loading, and an end-of-session review for learn mode. The project now feels more polished, more scalable, and better suited for replayability. Main Goal was just making the code easier to understand and implementing the Feedback. You can try it now . I would love to here some more feedback. <3
Devlog #1.3 Today I polished the game UI again and cleaned up some smaller details. I improved the help menu, made the top progress bar more visible, and changed the end screen so the leaderboard does not show up immediately. I also adjusted the main menu layout a little so the background has more space and the screen feels cleaner. Nothing huge today, but the game feels nicer and more polished now. The Help Button is a bit weird but I will fix it later.
Devlog #1.4 Today I worked more on polishing SpaceGuessr and making the special modes feel better. The biggest change was adding Reverse Learn , it’s a mode where the clue shows up in the middle of the screen first and then you have to guess the answer. I also improved the popup for missed images, polished some UI details like panels, spacing, and animations, and updated the README so it matches the current version better. Overall the game just feels cleaner and more finished now. And fun fact: I hit the stardance limit with this change, I saw just now that I could only commit 10h max. But I squeezed everything into the 10h. I will fix some stuff later like the loading times of the modes.
Devlog #1.5 Added a small local best score system to the main menu. It now checks saved leaderboard data in localStorage and shows the best score for the currently selected mode in a subtle way under the mode description. I also made sure it updates automatically when switching modes and after saving a run, while Daily , Learn , and Reverse Learn show a muted status message instead of a score because they are not normal saved score modes.
Devlog #1.6 Today I added a small profile in the right bottom. You can see your best scores and more. Everything is safed in localStorage, so no Account or smth. like that is needed.- I had to find an elegant way to save all the stats in localStorage, but I think it turned out well. I will have more time in the following days cause summer break started yesterday.
Devlog #1.7 I added the recent Runs to the Profile Menu and redesigned it, because it didn’t looked special. I think it has a smooth animation now. When there are bugs it would be cool if you could tell me. <3
Ships:
SpaceGuessr is like GeoGuessr, but in space. Explore planets, galaxies, nebulae, and more using real images provided by the NASA API. Guess where each image was taken or what it shows, compete for high scores, and climb the global leaderboard powered by Supabase.
SpaceGuessr is basically my version of “GeoGuessr, but in space” — a browser game where you guess planets, moons, nebulae, galaxies, and other space objects from real NASA-based images. At first, I thought this would just be a simple guessing game, but it quickly turned into a much bigger project. I kept adding more modes, more polish, better UI, scoring, animations, and content until it started to feel like an actual game instead of just a small prototype. Right now, SpaceGuessr has multiple game modes like Quick, Classic, Timed, Daily, Infinite, and Blind Reveal. Blind Reveal is one of my favorite parts: the image slowly uncovers itself while your possible score drops over time, so you have to decide whether to guess early or wait for more information. I also added a full scoring system with streak bonuses, animated feedback, end screens, keyboard controls, responsive design, leaderboard support, local fallback saving, confetti, reveal effects, round transitions, and a lot of small game-feel details. I spent a lot of time on these small things because they make the game feel much more satisfying to play. A big part of the work was also the content. The game uses a curated pool of 70+ NASA-based images, with correct answers, wrong answers, facts, and difficulty balancing. I kept improving the image pool so the game doesn’t feel repetitive, and I added logic so the same image won’t repeat during one run. Technically, the whole project is built with plain HTML, CSS, and JavaScript, without using a big framework. That meant a lot of the animations, UI states, game logic, scoring, and mode handling had to be built manually. I also added Supabase for global leaderboards and deployed everything with GitHub Pages so anyone can just open it and play instantly. I’m really proud of SpaceGuessr because it started as a simple idea and became one of my most complete projects so far. It’s playable, replayable, polished, and actually fun to come back to. I put a lot of time into making it feel smooth, finished, and cared for — and I think that shows in the final game. Thanks to everyone who is supporting this project <3
SpaceGuessr is a small browser game where you have to guess real space objects from NASA images. It works kinda like GeoGuessr, but instead of places on Earth you get planets, moons, nebulae, galaxies and other space stuff. The game has different modes like Classic, Timed, Blind Reveal, Learn and Reverse Learn, so you can either play for score or just practice. Technically the project is built with plain HTML, CSS and JavaScript, without any big framework. index.html contains the screens and buttons, style.css handles the layout, animations and responsive design, and script.js contains the main game logic like loading questions, checking answers, calculating score, streaks, timers, hints, leaderboards and local profile stats. The questions are stored in game-data.js, while mode settings like rounds, hints and timers are stored in game-config.js. The game also uses localStorage to save local stats, recent runs and fallback scores in the browser. For online scores it can use Supabase, but if that does not work the game still runs normally. Overall, SpaceGuessr is a space guessing game made with simple web technologys, real NASA images and a few extra features....
|
1792982878.0181184
|
1793069278.0181184
|
|
35107
|
Black Hole Simulation by @huncikoma | Stardance
|
huncikoma
|
1
|
99.0
|
1426
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-25T14:32:04Z", "hours": 99.0, "multiplier": 14.93, "payout": 1426, "blessing": "neutral", "text": "I made a real BlackHole simulation using python, Nvdia Cuda accelaration, It was very challenging to write the code plus understand the physics behind it as a 14 years old, the idea came from the Interstellar scene in the Black Hole simulation that the IBM supercomputer simulated. This is my version but this simulation is very power consuming, my 5070 hitting 2.2fps in the highest quality, I beg you dear reader to download and test it, because the demo site is just a demo not a real simulation, not Cuda and python like the real one if you download, and you can’t acces the settings that i made in the real so please download and try it not just the demo site because it is not the same feeling. Enjoy your trip at my simulated Black Hole. (Note: this is only works with Nvdia graphics card because of the Cuda (Sorry AMD))", "repo": "https://github.com/huncikoma-code/BlackHole", "demo": "https://huncikoma-code.github.io/BlackHole/"}]...
|
[{"post_id": 54436, "ts": "202 [{"post_id": 54436, "ts": "2026-08-25T13:25:05Z", "hours": 4.6667, "text": "Devlog#13 Finally, I finished the project, it is working, I created an install and a run batch file, and it is working, EVERYTHING!!! here a demonstration video (Sorry for the quality i have to shrinf from 201mb to 49mb) in the max level i’m getting 2.2 fps with a 5070!!!"}, {"post_id": 53013, "ts": "2026-08-23T12:14:59Z", "hours": 7.7, "text": "Devlog#12 Finally!!! I finished the main code, however I must do some bugfixes, and write a batch file to automaticly download python libaries, extensions , drivers to work. In the next devlog I can finally show you simulation footage."}, {"post_id": 52199, "ts": "2026-08-22T09:14:41Z", "hours": 9.1278, "text": "Devlog#11 In this section I worked a lot, I made the render section and the dynamic resolution scaling (auto mode)."}, {"post_id": 51555, "ts": "2026-08-21T10:22:36Z", "hours": 6.89, "text": "Devlog#10 Today I almost finished the Application part, doing some bug fixes, collecting the requirements, and I also did the rotating camera function and the orbit function as well"}, {"post_id": 50854, "ts": "2026-08-20T09:21:40Z", "hours": 7.7883, "text": "Devlog#9 Today I made the buffers and the screen size types to work but I can’t try it yet. because I has to finish the code"}, {"post_id": 49375, "ts": "2026-08-18T05:06:50Z", "hours": 7.5914, "text": "Devlog #8 I continued the aplication part, I made the screenshot option, this project is huge and I am very excited about it."}, {"post_id": 48740, "ts": "2026-08-17T08:35:41Z", "hours": 7.7036, "text": "Devlog#7 Finally I’m ready with the quality part, and I am working now on the Apllication and the Cuda drivers, In this section the Ai hellped me with the Cuda accelaration part because as I mentioned in my devlogs I didn’t work with Cuda before and I’m learning in the meantime with the help of Ai."}, {"post_id": 47345, "ts": "2026-08-15T07:12:43Z", "hours": 7.8725, "text": "Devlog#6 Today I worked around the graphics section more and I made the windows options: Fulscreen, windowed etc…"}, {"post_id": 46773, "ts": "2026-08-14T08:41:01Z", "hours": 5.1619, "text": "Devlog #5 In this part I fixed a lot of bugs around the cuda and the kernel section, I searched the compatible Cuda acceleration drivers."}, {"post_id": 45134, "ts": "2026-08-11T13:02:46Z", "hours": 7.0336, "text": "I made the Quallity settings for the reendering, I swear the 8K will be brutal."}, {"post_id": 39412, "ts": "2026-08-02T11:13:03Z", "hours": 8.2039, "text": "Devlog #3 — Post-processing and cameraRaw output from the renderer is HDR — values way above 1.0 around the disk."}, {"post_id": 38723, "ts": "2026-08-01T08:38:59Z", "hours": 5.7339, "text": "Devlog #2 — The render kernel Every pixel is one GPU thread, each tracing a photon backwards from the camera."}, {"post_id": 38110, "ts": "2026-07-31T10:13:41Z", "hours": 14.0203, "text": "Devlog #1: Black hole raytracer, the GPU side New project. This time it’s a real-time black hole renderer, including gravitational lensing and the accretion disk. It’s in Python, which feels familiar after working on the ISS tracker.The main idea is to shoot a ray for every pixel and bend it according to the Schwarzschild geodesic equation as it passes the black hole."}]...
|
Title: Black Hole Simulation by @huncikoma | Stard Title: Black Hole Simulation by @huncikoma | Stardance
Devlogs:
Devlog #1: Black hole raytracer, the GPU side New project. This time it’s a real-time black hole renderer, including gravitational lensing and the accretion disk. It’s in Python, which feels familiar after working on the ISS tracker.The main idea is to shoot a ray for every pixel and bend it according to the Schwarzschild geodesic equation as it passes the black hole.
Devlog #2 — The render kernel Every pixel is one GPU thread, each tracing a photon backwards from the camera.
Devlog #3 — Post-processing and cameraRaw output from the renderer is HDR — values way above 1.0 around the disk.
I made the Quallity settings for the reendering, I swear the 8K will be brutal.
Devlog #5 In this part I fixed a lot of bugs around the cuda and the kernel section, I searched the compatible Cuda acceleration drivers.
Devlog#6 Today I worked around the graphics section more and I made the windows options: Fulscreen, windowed etc…
Devlog#7 Finally I’m ready with the quality part, and I am working now on the Apllication and the Cuda drivers, In this section the Ai hellped me with the Cuda accelaration part because as I mentioned in my devlogs I didn’t work with Cuda before and I’m learning in the meantime with the help of Ai.
Devlog #8 I continued the aplication part, I made the screenshot option, this project is huge and I am very excited about it.
Devlog#9 Today I made the buffers and the screen size types to work but I can’t try it yet. because I has to finish the code
Devlog#10 Today I almost finished the Application part, doing some bug fixes, collecting the requirements, and I also did the rotating camera function and the orbit function as well
Devlog#11 In this section I worked a lot, I made the render section and the dynamic resolution scaling (auto mode).
Devlog#12 Finally!!! I finished the main code, however I must do some bugfixes, and write a batch file to automaticly download python libaries, extensions , drivers to work. In the next devlog I can finally show you simulation footage.
Devlog#13 Finally, I finished the project, it is working, I created an install and a run batch file, and it is working, EVERYTHING!!! here a demonstration video (Sorry for the quality i have to shrinf from 201mb to 49mb) in the max level i’m getting 2.2 fps with a 5070!!!
Ships:
I made a real BlackHole simulation using python, Nvdia Cuda accelaration, It was very challenging to write the code plus understand the physics behind it as a 14 years old, the idea came from the Interstellar scene in the Black Hole simulation that the IBM supercomputer simulated. This is my version but this simulation is very power consuming, my 5070 hitting 2.2fps in the highest quality, I beg you dear reader to download and test it, because the demo site is just a demo not a real simulation, not Cuda and python like the real one if you download, and you can’t acces the settings that i made in the real so please download and try it not just the demo site because it is not the same feeling. Enjoy your trip at my simulated Black Hole. (Note: this is only works with Nvdia graphics card because of the Cuda (Sorry AMD))...
|
1792878674.4165645
|
1793742674.4165645
|
|
47350
|
ReadBear by @Tulis | Stardance
|
Tulis
|
0
|
98.26
|
0
|
[]
|
[{"post_id": 80776, "ts": "202 [{"post_id": 80776, "ts": "2026-10-18T19:07:09Z", "hours": 5.1525, "text": "Devlog 17 I am so sorry for no devlogs! What did I do? i am still working on folders! they require a whole ui rewrite unfortunately! i got in contact with an artist, we are preparing some new logos and backgrounds! check samples in the pictures a lot of files changed (and I mean a lot - see in pictures) got everyting i18n-ated (all changelogs etc) file migrations (and custom screen!) What I will do next? folders. I will hopefully finish them to the next devlog! work on the custom logos and backgrounds! F-Droid: v0.8.1 Github: v0.8.1 Logo author: Castellon Artz"}, {"post_id": 79481, "ts": "2026-10-14T07:42:50Z", "hours": 6.3367, "text": "Devlog 16 What did I do in all this time? a lot of in-between things - for example githooks with tests (I pushed a bad build to f-droid, I need to learn on my mistakes ) a huge db migration - i am working on folders dates are in the ui (last read time, created at) you can now edit booktype-specific data working on folders! (a hugely big amount of work :<) What am I doing next? folders, snippet folders probably more tests update languages add some icons (a nice artist reached out to me!) See you in the next one! Get it on GitHub or F-Droid"}, {"post_id": 76833, "ts": "2026-10-04T19:20:07Z", "hours": 5.5144, "text": "Devlog 15 What have I been cooking in this much time? snippets! they are so pretty, you can zoom, see them pinterest-style, edit (with validation) and the cherry on top - you can now edit the selection! a lot of code updates and refactors added dates to DB (will add to UI in a sec!) file rename (almost all files had to be changed ) fixed a lot of random bugs fixed fdroid logo What will I do next? some suggestions from my friends :> fix bugs notes! local rating! local saving! a lot of customization! Github: v0.7.4 F-Droid: v0.7.4"}, {"post_id": 75623, "ts": "2026-09-30T16:08:55Z", "hours": 5.4036, "text": "Devlog 14 What have I done? (I am so happy ) I FIXED A BUG THAT WAS THERE FOR OVER A MONTH. It turns out I really had to thing outside-the-box (gosh I am so funny - cause yk - jetpack compose has boxes). The bug was caused when you press the back button quickly as it fades (as on video) a huge code refactor removed a bunch of bugs added viewing snippets, and saving them again i would want to empathize how happy I am and how much work the first one took XD got my website verificated with my signature I added an abstraction layer to menu - to help extend it further What I am working on? snippets (going back to the source) editing snippet details Thanks so much for reading this, I am so happy rn."}, {"post_id": 74893, "ts": "2026-09-28T15:18:42Z", "hours": 3.5053, "text": "Devlog 13 What changed? my code. really, most of the changes are to the quality of the code fixed covers not changing fixed editing (still working on it) added empty pages info (a pretty card) split pdf reading into 3 files (much more readable and maintainable code) moved navigation bar hiding/showing into separate file fixed random bugs still debuging the random empty page bug! What I am working on next? debuging random bugs! my todolist (currently bookmarks/editing) I also released the next version on F-Droid, with the updated logo! Github: v0.7.4 F-Droid: v0.7.4"}, {"post_id": 71896, "ts": "2026-09-21T18:34:38Z", "hours": 4.1192, "text": "Devlog 12 What changed? I moved out of vibecoded pdf library (sorry to say that, but it was terrible) snippets work now! there won’t be quotes as selecting in cbz’s and pdf is hard/non existable on mobile, but you can have cool snippets! attributions in snippets database migrations debuging, debuging and a lot of additional debuging fixed some bugs On what I will focus next? modifing snippets/deleting viewing a lot of code optimisations! On F-Droid: v0.7.2"}, {"post_id": 71095, "ts": "2026-09-20T09:05:52Z", "hours": 3.7536, "text": "Devlog 11 What changed? my app is now on F-Droid and the logo is clear (not blurry from my skill issue) new navigation menu zooming CBZs! working on quotes! fixed a library that i use for pdfs (hopefully they will accept the change XD) thinking how to do quotes for image-pdfs What I will focus on next? quotes bookmarks Release: v0.7.2 On F-Droid: v0.7.2 Please spread the beary news! See you in the next one"}, {"post_id": 67888, "ts": "2026-09-14T05:56:04Z", "hours": 3.195, "text": "Devlog 10 What changed? my app is now on F-Droid! we have tasty themes automatic translation credits fixed repo authors my icon on F-Droid is blurry What am I doing next: bookmarks quotes support for more formats? Thanks for sticking with me :) If you have any thoughts on themes (adding more!), create an issue! Release v0.7.0 F-Droid: https://f-droid.org/pl/packages/dev.tulis.readbear/"}, {"post_id": 66461, "ts": "2026-09-12T09:35:56Z", "hours": 3.2914, "text": "Devlog 9 MY APP GOT MERGED TO F-DROID! Yes, as you can see, I am a bit happy :) What changed: a lot of small changes to get my submition accepted you can select theme mode (dark, light, system) translation credits are now automatically added with GitHub actions added shrink options, my apk is now only ~25mb instead of 50mb! working on custom themes - catppuccin! relases are now stable! data migrations will be now in the repo What I am working on next: bookmarks and quotes collections/folders movable order of books (this is gonna be hard) adding the app to Google Play (at the end) Thanks for sticking with me! I am so happy that I got into F-Droid, after the merge in around 1-2 days you can go search ReadBear! (I will add the badge too) Relase: v0.6.3"}, {"post_id": 64869, "ts": "2026-09-09T15:44:35Z", "hours": 11.4844, "text": "Devlog 8 (a huge two i am so funny hahahahaha) What changed? epubs! (oh the horrors, this was so hard) three languages now: Polish, English and Russian i am in the process of adding my app to F-Droid (like it to help me!) Merge Request a lot of improvements to GitHub actions (caching, 4m build time reduced to ~30s!) reproducible builds and signing tasteful theme selection we don’t talk about the red cover. What is going on next? improving epubs we talk about the red cover. adding it to F-Droid adding the app to google play store :)"}, {"post_id": 62158, "ts": "2026-09-05T12:39:19Z", "hours": 7.8414, "text": "Devlog 7 (a huge one ) What changed? a beautiful new vector logo! app info page and proper versioning tests on github actions on translation fix translation to properly use plurals working on polish translation Gradle build now bundles translation credits from Weblate settings on pdf reader and an abstraction layer before it (easier future coding) fix a lot of bugs and memory leaks (who said that?) added a bunch of customization options added a split page function for funky pdfs What I will be working on next? Epubs Fixing visual bugs Release v0.3.0 See you in the next one!"}, {"post_id": 60437, "ts": "2026-09-02T19:27:39Z", "hours": 3.1744, "text": "Devlog 6 What I changed? added a configurable reading layout option for PDFs added a new book info page (so pretty!) fixed bugs and i18n issues there will be English, Russian, Polish translations! fixed code quality (a lot!) What am I doing next? Epubs More configurable options for PDFs and Epubs! Thanks for reading! Release v0.2.0"}, {"post_id": 60287, "ts": "2026-09-02T15:45:34Z", "hours": 7.0028, "text": "Devlog 5 (sorry for so little devlogs, hackatime was down ) What changed? Releases! Now the actions build and sign the app for releases (prereleases for now but yes) Pdf support! Full db rewrite More configurable options (and even more coming) A lot of bug fixes Got weblate set up for translating Bookmarks for PDFs A lot of metadata and info page! What am I doing next? Epubs - it is confirmed and doable :) More custom features and themes Make the info page human? Release: v0.1.0 See you in then next one!"}, {"post_id": 53837, "ts": "2026-08-24T15:09:45Z", "hours": 3.7392, "text": "Devlog 4 What have I changed? I created a Github actions builder that publishes the latest version to artifacts (releases later, as they are not ready XD) created lovely art and letterpaper (banner) also this tasty background changing depending on the theme) I am in the middle of completely changing the db structure to accommodate PDFs and EPUBs many code optimisations I will focus on? PDFs for now more themes See you in the next one!"}, {"post_id": 52541, "ts": "2026-08-22T18:20:20Z", "hours": 2.9881, "text": "Devlog 3 What have I done? full i18n-ation (every text is in strings file, so it can be translated), english as of now (russian and polish are coming) you can zoom the panels so you can adore all the details settings now has tabs so more options can be added settings popout extends all the way instead of a akward middleway settings are actually saved when pressing the “Save” button (yes they were discarded when saving, and saved when pressing somewhere else 🤭) What I will be working on? hopefully epubs removing all the bugs 🐛 making it even more customizable (custom backgrounds and themes are coming!) See you in the next one!"}, {"post_id": 50473, "ts": "2026-08-19T17:14:15Z", "hours": 10.8378, "text": "Devlog 2 (omg I am writing this third time, I need to copy it this time) What I changed? added bookmarks (auto remembering where you last read) added beautiful coffee theme added customization options added rereading (am I the only one to reread books/mangas all the time?) fixed bugs and memory leaks (memory leaks in an android app, I know) On what I will focus now? writing more frequent devlogs I18N - aside from polish, english and probably russian maybe EPUBS 💀 fix some annoying bugs (such as the cover sometimes not changing) I created a Github repo! See you in the next one!"}, {"post_id": 46229, "ts": "2026-08-13T10:11:01Z", "hours": 10.9167, "text": "Devlog 1, what it is? ReadBear is a cute app for reading Comics (.cbz) and hopefully EPUB books! It is written in Jetpack Compose and will be Android only. What have I done? I made importing the comics/mangas through file, adding it to database and indexing for reading. You can click on the comic/manga and start to read it! There is some customising options but not that many as I would like in the finished product This is my first Android app! I really love the Material Design and UI so I am happy to use Compose! This is my first time in Kotlin (coming from Java) so it is a bit confusing, but I like it! Ooopsies! I forgot to create a project and post devlogs on this app!"}]...
|
Title: ReadBear by @Tulis | Stardance
Devlogs:
De Title: ReadBear by @Tulis | Stardance
Devlogs:
Devlog 1, what it is? ReadBear is a cute app for reading Comics (.cbz) and hopefully EPUB books! It is written in Jetpack Compose and will be Android only. What have I done? I made importing the comics/mangas through file, adding it to database and indexing for reading. You can click on the comic/manga and start to read it! There is some customising options but not that many as I would like in the finished product This is my first Android app! I really love the Material Design and UI so I am happy to use Compose! This is my first time in Kotlin (coming from Java) so it is a bit confusing, but I like it! Ooopsies! I forgot to create a project and post devlogs on this app!
Devlog 2 (omg I am writing this third time, I need to copy it this time) What I changed? added bookmarks (auto remembering where you last read) added beautiful coffee theme added customization options added rereading (am I the only one to reread books/mangas all the time?) fixed bugs and memory leaks (memory leaks in an android app, I know) On what I will focus now? writing more frequent devlogs I18N - aside from polish, english and probably russian maybe EPUBS 💀 fix some annoying bugs (such as the cover sometimes not changing) I created a Github repo! See you in the next one!
Devlog 3 What have I done? full i18n-ation (every text is in strings file, so it can be translated), english as of now (russian and polish are coming) you can zoom the panels so you can adore all the details settings now has tabs so more options can be added settings popout extends all the way instead of a akward middleway settings are actually saved when pressing the “Save” button (yes they were discarded when saving, and saved when pressing somewhere else 🤭) What I will be working on? hopefully epubs removing all the bugs 🐛 making it even more customizable (custom backgrounds and themes are coming!) See you in the next one!
Devlog 4 What have I changed? I created a Github actions builder that publishes the latest version to artifacts (releases later, as they are not ready XD) created lovely art and letterpaper (banner) also this tasty background changing depending on the theme) I am in the middle of completely changing the db structure to accommodate PDFs and EPUBs many code optimisations I will focus on? PDFs for now more themes See you in the next one!
Devlog 5 (sorry for so little devlogs, hackatime was down ) What changed? Releases! Now the actions build and sign the app for releases (prereleases for now but yes) Pdf support! Full db rewrite More configurable options (and even more coming) A lot of bug fixes Got weblate set up for translating Bookmarks for PDFs A lot of metadata and info page! What am I doing next? Epubs - it is confirmed and doable :) More custom features and themes Make the info page human? Release: v0.1.0 See you in then next one!
Devlog 6 What I changed? added a configurable reading layout option for PDFs added a new book info page (so pretty!) fixed bugs and i18n issues there will be English, Russian, Polish translations! fixed code quality (a lot!) What am I doing next? Epubs More configurable options for PDFs and Epubs! Thanks for reading! Release v0.2.0
Devlog 7 (a huge one ) What changed? a beautiful new vector logo! app info page and proper versioning tests on github actions on translation fix translation to properly use plurals working on polish translation Gradle build now bundles translation credits from Weblate settings on pdf reader and an abstraction layer before it (easier future coding) fix a lot of bugs and memory leaks (who said that?) added a bunch of customization options added a split page function for funky pdfs What I will be working on next? Epubs Fixing visual bugs Release v0.3.0 See you in the next one!
Devlog 8 (a huge two i am so funny hahahahaha) What changed? epubs! (oh the horrors, this was so hard) three languages now: Polish, English and Russian i am in the process of adding my app to F-Droid (like it to help me!) Merge Request a lot of improvements to GitHub actions (caching, 4m build time reduced to ~30s!) reproducible builds and signing tasteful theme selection we don’t talk about the red cover. What is going on next? improving epubs we talk about the red cover. adding it to F-Droid adding the app to google play store :)
Devlog 9 MY APP GOT MERGED TO F-DROID! Yes, as you can see, I am a bit happy :) What changed: a lot of small changes to get my submition accepted you can select theme mode (dark, light, system) translation credits are now automatically added with GitHub actions added shrink options, my apk is now only ~25mb instead of 50mb! working on custom themes - catppuccin! relases are now stable! data migrations will be now in the repo What I am working on next: bookmarks and quotes collections/folders movable order of books (this is gonna be hard) adding the app to Google Play (at the end) Thanks for sticking with me! I am so happy that I got into F-Droid, after the merge in around 1-2 days you can go search ReadBear! (I will add the badge too) Relase: v0.6.3
Devlog 10 What changed? my app is now on F-Droid! we have tasty themes automatic translation credits fixed repo authors my icon on F-Droid is blurry What am I doing next: bookmarks quotes support for more formats? Thanks for sticking with me :) If you have any thoughts on themes (adding more!), create an issue! Release v0.7.0 F-Droid: https://f-droid.org/pl/packages/dev.tulis.readbear/
Devlog 11 What changed? my app is now on F-Droid and the logo is clear (not blurry from my skill issue) new navigation menu zooming CBZs! working on quotes! fixed a library that i use for pdfs (hopefully they will accept the change XD) thinking how to do quotes for image-pdfs What I will focus on next? quotes bookmarks Release: v0.7.2 On F-Droid: v0.7.2 Please spread the beary news! See you in the next one
Devlog 12 What changed? I moved out of vibecoded pdf library (sorry to say that, but it was terrible) snippets work now! there won’t be quotes as selecting in cbz’s and pdf is hard/non existable on mobile, but you can have cool snippets! attributions in snippets database migrations debuging, debuging and a lot of additional debuging fixed some bugs On what I will focus next? modifing snippets/deleting viewing a lot of code optimisations! On F-Droid: v0.7.2
Devlog 13 What changed? my code. really, most of the changes are to the quality of the code fixed covers not changing fixed editing (still working on it) added empty pages info (a pretty card) split pdf reading into 3 files (much more readable and maintainable code) moved navigation bar hiding/showing into separate file fixed random bugs still debuging the random empty page bug! What I am working on next? debuging random bugs! my todolist (currently bookmarks/editing) I also released the next version on F-Droid, with the updated logo! Github: v0.7.4 F-Droid: v0.7.4
Devlog 14 What have I done? (I am so happy ) I FIXED A BUG THAT WAS THERE FOR OVER A MONTH. It turns out I really had to thing outside-the-box (gosh I am so funny - cause yk - jetpack compose has boxes). The bug was caused when you press the back button quickly as it fades (as on video) a huge code refactor removed a bunch of bugs added viewing snippets, and saving them again i would want to empathize how happy I am and how much work the first one took XD got my website verificated with my signature I added an abstraction layer to menu - to help extend it further What I am working on? snippets (going back to the source) editing snippet details Thanks so much for reading this, I am so happy rn.
Devlog 15 What have I been cooking in this much time? snippets! they are so pretty, you can zoom, see them pinterest-style, edit (with validation) and the cherry on top - you can now edit the selection! a lot of code updates and refactors added dates to DB (will add to UI in a sec!) file rename (almost all files had to be changed ) fixed a lot of random bugs fixed fdroid logo What will I do next? some suggestions from my friends :> fix bugs notes! local rating! local saving! a lot of customization! Github: v0.7.4 F-Droid: v0.7.4
Devlog 16 What did I do in all this time? a lot of in-between things - for example githooks with tests (I pushed a bad build to f-droid, I need to learn on my mistakes ) a huge db migration - i am working on folders dates are in the ui (last read time, created at) you can now edit booktype-specific data working on folders! (a hugely big amount of work :<) What am I doing next? folders, snippet folders probably more tests update languages add some icons (a nice artist reached out to me!) See you in the next one! Get it on GitHub or F-Droid
Devlog 17 I am so sorry for no devlogs! What did I do? i am still working on folders! they require a whole ui rewrite unfortunately! i got in contact with an artist, we are preparing some new logos and backgrounds! check samples in the pictures a lot of files changed (and I mean a lot - see in pictures) got everyting i18n-ated (all changelogs etc) file migrations (and custom screen!) What I will do next? folders. I will hopefully finish them to the next devlog! work on the custom logos and backgrounds! F-Droid: v0.8.1 Github: v0.8.1 Logo author: Castellon Artz...
|
1792511584.1076407
|
1793116384.1076407
|
|
38495
|
Habit Tracker by @FusionLord | Stardance
|
FusionLord
|
1
|
98.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T20:25:18Z", "hours": 98.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a tool to help people track their habits while keeping it all local so no one else sees your data! I learnt a lot of java and css in this project and mostly had difficulty with the storage system, still quite proud of it though. To test it just use github pages unless you also want to try downloading it to use the html. Have fun :)", "repo": "https://github.com/Fusion-4/Habit-Tracker", "demo": "https://fusion-4.github.io/Habit-Tracker/"}]...
|
[{"post_id": 63828, "ts": "202 [{"post_id": 63828, "ts": "2026-09-07T20:02:54Z", "hours": 4.3703, "text": "Devlog 12- Everything works now! All of the features are officially working on github pages! To recap some of the latest features, you can add a custom background and change transparency, duplicate habit warning, and multiple pages for your habits."}, {"post_id": 63607, "ts": "2026-09-07T15:13:27Z", "hours": 9.4539, "text": "Devlog 11 - I will start tweaking This was meant to be my final devlog-> I fixed a lot of the problems but apparently a lot of the buttons are broken now :/ Hopefully done next update."}, {"post_id": 54881, "ts": "2026-08-26T02:54:32Z", "hours": 10.1897, "text": "Day 8! (I’m procrastinating a lot) Today I finished up the UI transformation so now it can have a custom background and change the opacity of the blocks. (For some reason github pages won’t load the settings ui so for now I’m using live server.) There are a few problems like text clipping into each other which will be fixed next devlog. I also want to fix the calendar date scaling and make it so habit has about 3 it shows and you can click through to see them all without increasing vertical space."}, {"post_id": 49296, "ts": "2026-08-18T01:07:37Z", "hours": 10.2206, "text": "Day 7! (I spent like 2 days on this) I broke the css into multiple parts and made the layout for desktop look much cleaner, now its wider so you don’t have to scroll for 3 years just to find your statistics. I also still need to remove a few things but otherwise this is pretty good. I want to spend the next day making the UI look a little better. I also want to make a separate settings UI so its cleaner overall."}, {"post_id": 44377, "ts": "2026-08-10T02:52:06Z", "hours": 9.9719, "text": "Day 6! I finally finished breaking down the Javascript! Now a lot of features work, such as a bunch of statistics, leaderboard, calendar, and a basic dashboard. I am pretty proud of the storage system I added so you can export and import your data. I don’t know if syncing is possible, if it is I will attempt to add it. I don’t like the fact that I need to scroll (at least on desktop). I plan to fix this but still thing about a good layout. I added a loading screen but its super useless so I will get rid of it. I added a super lazy fix to the css so I need to fix that tmrw."}, {"post_id": 41014, "ts": "2026-08-04T22:12:31Z", "hours": 9.4019, "text": "Day 5 - My javascript is 100% broken I wanted to make this devlog not only to log my hours but explain why I spent 9 hours and am still having problems. I’ve spent some time recoding the project because there were a lot of issues with how I was coding before (aka writing a bunch of code that just didn’t work). I have been working on making the code cleaner and when trying it my Javascript is broken. More and more reasons to break my javascript into multiple files -> Doing that next, hopefully its easy 😭 As you can see its pretty cooked."}, {"post_id": 36161, "ts": "2026-07-28T02:18:57Z", "hours": 9.8558, "text": "… I realized that I cut out half of the code… (I will be back in a few minutes!)"}, {"post_id": 35573, "ts": "2026-07-27T03:22:30Z", "hours": 2.4319, "text": "Day 4 - Part 2! Finally fixed the bug and changed the UI a little more, still feels a little off though. I added a lot of Qol features such as renaming, favoriting, notes, categories, search bar, and a progress bar. You can also now see when you last did the task/habit."}, {"post_id": 35522, "ts": "2026-07-27T00:31:51Z", "hours": 10.0864, "text": "Day 4 of Habit Tracker! Well…. somehow after 10+ hours of coding I didn’t find the bug until now. I spent the whole time adding Qol features but I will fix the bug first before explaining the added features."}, {"post_id": 34954, "ts": "2026-07-26T02:23:37Z", "hours": 10.0533, "text": "Day 3 of Habit Tracker! Today I worked on adding a bunch of UI resizing formats so the phone section now works without squishing the UI. I added a history and daily completion system so now the overall experience is better. I’m thinking of a UI update in the future to make this look more cozy!"}, {"post_id": 34394, "ts": "2026-07-25T02:30:19Z", "hours": 8.3817, "text": "Day 2 of this Project! Today I rebuilt much of the Habit Tracker to create a cleaner foundation for future updates. I redesigned the interface, separated the HTML, CSS, and JavaScript into their own files, and rebuilt the habit system for adding, deleting, and saving habits with Local Storage. This now works on phones and linux but I do want to tweak the theme a little more. I also want to fix the phone support because everything looks a little squished right now. I spent a whole hour trying to get github pages to update after this."}, {"post_id": 33783, "ts": "2026-07-23T23:43:17Z", "hours": 3.9014, "text": "Started the project today! Habit tracker should explain itself, but here is a quick one-liner. - A simple web app for tracking daily habits and building consistent routines. I spent a while making this work and I have a simple GUI built, nothing crazy. As of now you can switch between dark and light mode and add or delete tasks. I also got the system to save data working! A few problems are the emojis and font size not rendering properly on linux, and the java not working on phones. (Will be working on these problems tomorrow) I spent 2 hours after this trying to figure out how to make a commit."}]...
|
Title: Habit Tracker by @FusionLord | Stardance
D Title: Habit Tracker by @FusionLord | Stardance
Devlogs:
Started the project today! Habit tracker should explain itself, but here is a quick one-liner. - A simple web app for tracking daily habits and building consistent routines. I spent a while making this work and I have a simple GUI built, nothing crazy. As of now you can switch between dark and light mode and add or delete tasks. I also got the system to save data working! A few problems are the emojis and font size not rendering properly on linux, and the java not working on phones. (Will be working on these problems tomorrow) I spent 2 hours after this trying to figure out how to make a commit.
Day 2 of this Project! Today I rebuilt much of the Habit Tracker to create a cleaner foundation for future updates. I redesigned the interface, separated the HTML, CSS, and JavaScript into their own files, and rebuilt the habit system for adding, deleting, and saving habits with Local Storage. This now works on phones and linux but I do want to tweak the theme a little more. I also want to fix the phone support because everything looks a little squished right now. I spent a whole hour trying to get github pages to update after this.
Day 3 of Habit Tracker! Today I worked on adding a bunch of UI resizing formats so the phone section now works without squishing the UI. I added a history and daily completion system so now the overall experience is better. I’m thinking of a UI update in the future to make this look more cozy!
Day 4 of Habit Tracker! Well…. somehow after 10+ hours of coding I didn’t find the bug until now. I spent the whole time adding Qol features but I will fix the bug first before explaining the added features.
Day 4 - Part 2! Finally fixed the bug and changed the UI a little more, still feels a little off though. I added a lot of Qol features such as renaming, favoriting, notes, categories, search bar, and a progress bar. You can also now see when you last did the task/habit.
… I realized that I cut out half of the code… (I will be back in a few minutes!)
Day 5 - My javascript is 100% broken I wanted to make this devlog not only to log my hours but explain why I spent 9 hours and am still having problems. I’ve spent some time recoding the project because there were a lot of issues with how I was coding before (aka writing a bunch of code that just didn’t work). I have been working on making the code cleaner and when trying it my Javascript is broken. More and more reasons to break my javascript into multiple files -> Doing that next, hopefully its easy 😭 As you can see its pretty cooked.
Day 6! I finally finished breaking down the Javascript! Now a lot of features work, such as a bunch of statistics, leaderboard, calendar, and a basic dashboard. I am pretty proud of the storage system I added so you can export and import your data. I don’t know if syncing is possible, if it is I will attempt to add it. I don’t like the fact that I need to scroll (at least on desktop). I plan to fix this but still thing about a good layout. I added a loading screen but its super useless so I will get rid of it. I added a super lazy fix to the css so I need to fix that tmrw.
Day 7! (I spent like 2 days on this) I broke the css into multiple parts and made the layout for desktop look much cleaner, now its wider so you don’t have to scroll for 3 years just to find your statistics. I also still need to remove a few things but otherwise this is pretty good. I want to spend the next day making the UI look a little better. I also want to make a separate settings UI so its cleaner overall.
Day 8! (I’m procrastinating a lot) Today I finished up the UI transformation so now it can have a custom background and change the opacity of the blocks. (For some reason github pages won’t load the settings ui so for now I’m using live server.) There are a few problems like text clipping into each other which will be fixed next devlog. I also want to fix the calendar date scaling and make it so habit has about 3 it shows and you can click through to see them all without increasing vertical space.
Devlog 11 - I will start tweaking This was meant to be my final devlog-> I fixed a lot of the problems but apparently a lot of the buttons are broken now :/ Hopefully done next update.
Devlog 12- Everything works now! All of the features are officially working on github pages! To recap some of the latest features, you can add a custom background and change transparency, duplicate habit warning, and multiple pages for your habits.
Ships:
I made a tool to help people track their habits while keeping it all local so no one else sees your data! I learnt a lot of java and css in this project and mostly had difficulty with the storage system, still quite proud of it though. To test it just use github pages unless you also want to try downloading it to use the html. Have fun :)...
|
1793004479.5640514
|
1793090879.5640514
|
|
33169
|
Starweb by @mixidmb | Stardance
|
mixidmb
|
0
|
97.91
|
0
|
[]
|
[{"post_id": 62169, "ts": "202 [{"post_id": 62169, "ts": "2026-09-05T13:03:28Z", "hours": 2.6939, "text": "Starweb dev log #22 Context menu, the three-dot button, has New Tab, History, Zoom, and Clear History as of right now. History saves to disk like localStorage; icons are cached per origin. The menu shows the last 5 visits (I will make a page where you can browse more)."}, {"post_id": 58507, "ts": "2026-08-30T22:51:21Z", "hours": 2.0131, "text": "Starweb dev log #21 Pages can save data now: localStorage , per origin. Origin is scheme, host, and port, so moon:// and star:// don’t share a store. getItem / setItem / removeItem / clear / key , indexing ( localStorage[k] = v ), .length . Capped at 4096 keys, 5MB per origin. Sources in DevTools has a Storage group, with Delete and Clear buttons."}, {"post_id": 56941, "ts": "2026-08-28T23:36:33Z", "hours": 1.0008, "text": "Starweb dev log #20 Zoom feature. Ctrl/Cmd +/-/0, or Ctrl+scroll over the page. Goes through steps from 25% to 300%, same as a real browser, with a small pill in the corner showing the percentage and a Reset button that fades when not zooming anymore."}, {"post_id": 56242, "ts": "2026-08-27T22:27:16Z", "hours": 3.1422, "text": "Starweb dev log #19 Sources panel. It lists everything the page fetched, grouped into: Document, Scripts, Stylesheets, Images, Media, Fonts. Text files have a viewer, wrap toggle, find-in-file, and line numbers. Images show the texture. Media points to the page’s own player rather than opening a second stream, since a URL only has one range cache."}, {"post_id": 51962, "ts": "2026-08-21T22:59:30Z", "hours": 5.6958, "text": "Starweb dev log #18 (woah didn’t devlog for a while) Network tab and DevTools got restyled to match the rest. Every request now gets timed in stages: resolve, connect, TLS, send, wait, download, each stamped as it happens inside perform_request . The panel draws that as a bar per stage, plus headers, response preview, and a security tab with the TLS info for that request. Then the devtools were redesigned to match the browser style from the last devlog."}, {"post_id": 39772, "ts": "2026-08-02T23:24:18Z", "hours": 2.2144, "text": "Starweb dev log #17 Restyled the browser to match Nebula, and gave it real icons. The toolbar and tab icons used to be hand-drawn with ImGui lines. Now they’re Lucide SVGs, rasterized once and tinted. Layout used to be random numbers everywhere; now it’s all one Trim namespace. Colors follow one ramp: dim, then mid, then bright when focused."}, {"post_id": 38294, "ts": "2026-07-31T16:41:39Z", "hours": 6.7392, "text": "Starweb dev log #16 DevTools! F12 or Cmd/Ctrl+Shift+I opens a dock on the right side of the page. Elements works: a picker button lets you click something on the page to select it, or walk the DOM tree directly. Selecting a node shows its computed styles and box model, with real layout padding rather than just the CSS value. Console works too. Whatever you type evaluates in that tab’s own Lua engine, with history on up/down. Network, Sources, and Metrics are just tabs for now, not built yet. Im going to be working on design now"}, {"post_id": 37609, "ts": "2026-07-30T13:55:03Z", "hours": 3.6256, "text": "Starweb dev log #15 Added live search and SVG rendering. Type in the sidebar or the home search, and a dropdown fills in as you go. That needed a new input event for page scripts, they only got click before. Queries are percent-encoded before they hit the URL, with a small urlenc() since this runtime has no encodeURIComponent . Also added recent pages on the home screen, capped at 3, deduped, ordered so two clicks in the same instant land right."}, {"post_id": 37045, "ts": "2026-07-29T14:44:16Z", "hours": 2.8836, "text": "Starweb dev log #14 Analytics got a range picker, and the drawing underneath it got a lot cheaper to run. The panel graphs now go from 1h up to 1y, not just a fixed 14 days. That needed a second counter: stats_min , one document per domain per minute, which only exists to answer the sub-day windows and ages out on a TTL index. The old daily stats collection stays forever so the all-time total is still exact. Past a month the buckets widen to weeks then 30-day chunks, since 180 daily points would just read as a smear at chart width. The nebula background got refactored for speed: prep() runs once per canvas resize and does all the expensive math, square roots, atan2 , walking every line segment, into a flat array; lit() runs per frame and just reads that array plus whatever actually changes frame to frame (the shine position, the cog’s rotation). Same picture, way less work per frame. Hex color parsing got a fast path too, since a canvas setting fillStyle per dot was hitting the full color parser thousands of times a frame for the one form it ever uses. Canvas itself grew a few things: fillRect / strokeRect take an optional radius now, measureText reads the actual font the page pushed instead of the UI default, and hoverX / hoverY are readable off a canvas element. The ctx method lookup also switched from a chain of strcmp to a real table, since a heavy canvas loop calls into it constantly. requestAnimationFrame self-paces now. A callback that runs long gets a gap after it sized to what it just cost, capped at 500ms, so one expensive canvas can’t eat the whole frame budget. It also only fires for the visible tab and stops while the window’s minimized; timers and fetches keep going regardless, same as a background tab in a real browser."}, {"post_id": 36067, "ts": "2026-07-27T22:23:33Z", "hours": 4.5206, "text": "Starweb dev log #13 Added analytics and worked on the domains page. The resolver bumps a counter every time it answers a lookup: one document per domain per day, not per query. It’s best-effort: if the analytics write fails, the answer still goes out. Missing days are zero-filled, so a new domain shows a flat line instead of a gap. That feeds two chart types in Lua, chartBars and chartLine , just canvas: fillRect bars or a stroked polyline. Zero draws nothing, and only a real value gets a 2px floor. The home page gets one combined trend line across every domain, the domains list gets a sparkline per row. Also fixed a flex-grow input because it didn’t fill its row width. Inputs and textareas now stretch to match, so form rows line up."}, {"post_id": 34592, "ts": "2026-07-25T13:28:40Z", "hours": 3.8811, "text": "Starweb dev log #12 I started redesigning the panel. Signed in, you land on a sidebar with tabs (home, domains, analytics), a search bar, and a home page. (Cloudflare copy ik lol) The sidebar icons are Lucide SVGs. Those are drawn on a 24x24 grid and use way more of the SVG path language than my login art did: relative commands, H / V , arcs, closepath, plus <circle> elements. The browser has no SVG parser yet (but ig it’s unavoidable at this point), so I wrote a script ( shapes.py ) that reads each icon once and flattens it into plain points, arcs, and all. Those points get baked straight into the page’s Lua as a table, so the page itself is just normal HTML and Lua, no different from any other page, and the script just loops over the points and draws them. Rendering also looks sharper now. Layout and drawing account for the framebuffer scale, so the vector art doesn’t go blurry on a hi-DPI window anymore."}, {"post_id": 34046, "ts": "2026-07-24T14:26:36Z", "hours": 3.1742, "text": "Starweb devlog #11 Nebula login page design. I don’t have much to talk about today, so enjoy the video."}, {"post_id": 33558, "ts": "2026-07-23T16:21:58Z", "hours": 9.2311, "text": "Starweb dev log #10 Starweb has domains now. There’s .web , with a DNS behind it. StarDNS (name is temporary) is an authoritative server for the .web zone. It answers over UDP, falls back to TCP when a reply won’t fit, and reads records out of MongoDB. Three parts in one process: the resolver, a panel to manage names, and a CA that issues star:// certs. the panel Sign in, and you get three domains, each a single label under .web . Records are A , AAAA , CNAME , TXT with a TTL from 60 to 86400. The rules a resolver relies on are enforced on the way in: a CNAME can’t share a name with another record or sit at the apex. @ is the domain itself, *.dev is a wildcard, and a CNAME target with no dot is relative. It’s served with the starweb package, so you browse it in Starmap like any page. Every action is also a JSON route, so it’s scriptable from starweb post . certificates “Issue certificate” makes a P-256 leaf covering mysite.web and *.mysite.web , signed by the StarWeb root, valid 825 days. Stored in Mongo and written to dns/issued/ ; the key never touches the database. The root is name-constrained to .web now, so it can’t issue for a public name; ca.issue(\"www.google.com\") fails its own verify, and a test holds it there. resolving The browser and client resolve .web themselves. A host in the zone gets asked straight to StarDNS over UDP ( src/common/resolver.hpp ), never getaddrinfo , which would leak the lookup to a public DNS. No fallback: if StarDNS can’t answer, the load fails instead of quietly asking the public resolver. Anything that isn’t .web still goes to the system resolver. It chases CNAMEs, queries A and AAAA separately, and caches by TTL so a page’s subresources cost one lookup. Point it elsewhere with STARWEB_DNS , or STARWEB_DNS=off to fall back. Next is the look of the website."}, {"post_id": 33025, "ts": "2026-07-22T16:03:30Z", "hours": 5.2942, "text": "Starweb dev log #9 Media streams now instead of downloading the whole file first. A big MP4 used to sit there until every byte landed. Now there’s a MediaSource : a seekable view of the remote file that fills in as it’s read, so the decoder starts on the first megabyte while the rest is still downloading. It runs on Range requests. The server advertises Accept-Ranges: bytes and answers bytes=a-b , bytes=a- , or bytes=-n (trailing bytes, how a player finds an MP4’s moov atom) with 206 . Bad or multi-range requests get 416 . It streams the file out in chunks rather than loading it into memory, so the server side is cheap too. On the browser, chunks land in a sparse cache file in 64KB pieces, and a read only blocks on the chunks it touches. A .ranges sidecar tracks what’s present; once it’s all there, the file is the cache entry. Seeking doesn’t wait behind the sequential download; hint_seek steers the prefetcher to where you jumped. Both backends got wired in: FFmpeg through custom IO, macOS through AVAssetResourceLoader . Cache pruning counts real bytes on disk now and cleans up the .ranges sidecars, and there are range tests on the Python side ( bytes=a-b , EOF, suffix, 416 , clamping)."}, {"post_id": 31553, "ts": "2026-07-20T01:39:32Z", "hours": 2.7467, "text": "Starweb dev log #8 Page scripts can fetch() now. fetch(\"/api/time\", function(err, res) ... end) runs on a worker thread and calls you back when it’s done, so the page never freezes. You get res.status , res.ok , res.body , res.headers , and res:json() . POST works too: fetch(\"/api/echo\", { method = \"POST\", json = { hi = \"there\" } }, cb) . There’s a json global with it ( json.encode / json.decode ). Limits: 6 fetches at a time, 1MB request body, 8MB response, caps on headers, URL length, and JSON depth. Cross-origin requests are CORS-gated by browsers; a fetch to another host only returns a body if it sends Access-Control-Allow-Origin . The Python server got a per-route cors= option to match. Also refactored the fetcher: one perform_request with RequestOptions (method, headers, body, timeouts, max size), and perform_fetch is a thin wrapper for navigations on top. Scripted fetch and the address bar share code now instead of two separate socket loops."}, {"post_id": 31432, "ts": "2026-07-19T19:57:32Z", "hours": 4.5981, "text": "StarWeb dev log #7 You can write StarWeb backends in Python now. Everything so far has been C++. Writing a page that did anything meant static files or a Lua script in the browser. So there’s now a starweb Python package that speaks STWP, in two halves. The server half looks like Flask. Make an App , decorate functions with @app.route(\"/api/time\") , return a dict, and it goes out as JSON, or a Response for control over status and headers. Routes take params ( /api/greet/<name> ), the request has a query dict, and app.mount_static(\"/\", \"www\") serves files with routes winning over static. app.run(scheme=\"both\") hosts moon:// and star:// at once, thread per connection, same as the C++ server. The client half looks like requests. starweb.get(\"moon://localhost/\") , .post(...) , a Session to reuse a connection, and TLS for star:// with each failure getting its own exception ( TLSVerificationError , MixedContentError , ALPNError ). it only speaks STWP The interesting part is what it refuses. Send the server an HTTP request line, and it answers 505 and hangs up; curl and a browser can’t wander in by accident. The client trusts only the StarWeb root CA, never the system roots, and it’s pinned to TLS 1.3 and nothing else. ALPN is required: no stwp/1.0 , connection dropped. the CLI starweb get moon://localhost/index.html fetches a URL, -v for headers and TLS info. starweb serve app.py runs a file defining an App , with --scheme , --no-tls , --log . curl and a dev server in one command. It’s a proper pip package too: README, license, pyproject.toml , pip install starweb and you get a starweb command. And there are tests: interop against the C++ server, URL and message parsing, schemes, isolation, which caught a couple of parser mismatches between the two."}, {"post_id": 29865, "ts": "2026-07-17T00:52:51Z", "hours": 4.0061, "text": "StarWeb dev log #6 StarWeb has secure connections now: star:// . star:// is to moon:// what https is to http : same STWP messages; the transport underneath is just TLS 1.3 (OpenSSL 3) instead of plaintext TCP. Plaintext moon:// stays on port 8090, encrypted star:// runs on 8490, and the server serves both at once. There’s a tools/make_certs.sh that spins up a local root CA and a server cert so you can test it. The CA only signs localhost , .local / .star , and private IPs ( 10.x , 192.168.x , etc.), so it works on your LAN but not the public internet. (I it will be public after i make DNS) The address bar got a lock icon. Click it, and you get a cert info popup: who issued it, who it’s for, that kind of thing. If the handshake fails, verification fails, cert’s self-signed, expired, wrong host, you get a full-page interstitial instead of the page, same as a real browser yells at you. the security rules A star:// page can’t pull in moon:// content. Mixed content is blocked; no loading plaintext resources into a page you’re being told is secure. Downgrades are blocked too, and stricter than the normal web; here, a script can’t navigate you from star:// to moon:// . You can still type a moon:// URL yourself; that’s your call, but a page can’t quietly drop you off TLS. TLS also enforces ALPN and checks the hostname, and there’s a session resumption cache so reconnecting doesn’t redo the whole handshake every time. Also fixed URL parsing to handle IPv6 addresses in brackets ( [::1] ), which it just choked on before."}, {"post_id": 29198, "ts": "2026-07-15T22:45:12Z", "hours": 6.1247, "text": "StarWeb dev log #5 Lua support! Every tab gets its own ScriptEngine , a sandboxed Lua 5.4 interpreter. A custom allocator caps its memory, an instruction hook kills it when it runs past its time budget, and require , dofile , and loadfile don’t exist in there. It’s untrusted code from whatever page you loaded. Scripts get a DOM API: getElementById , querySelector , innerText , get / setAttribute , addEventListener , console.log , alert , setTimeout / setInterval , requestAnimationFrame . There’s a location object too, so scripts can navigate, but only to moon:// URLs. Yes, there is <canvas> . getContext(\"2d\") gives you fillRect , paths, arcs, fillText , but scripts never touch the screen directly; every call gets recorded into a list of CanvasOp s and the renderer draws the list. To test all of it, I wrote a raycaster ( www/game.lua ), a small maze you can walk around in, running entirely as a page script. external scripts and keyboard input <script src=\"...\"> works, not just inline scripts. The fetcher downloads them so the engine sees them in document order. Keyboard input works too; keys get polled from GLFW and sent to the active tab, so document.addEventListener(\"keydown\", ...) does something. That’s how the raycaster gets its controls. The main loop also stopped redrawing at 60fps when nothing’s happening. It sleeps until something needs a frame: a fetch, a playing video, a pending timer, or requestAnimationFrame . Good for the battery. (My MacBook 2015 was on fire when the browser ran. That’s how I noticed lol) Also, from now on I will be posting more devlogs because im done with the core stuff. Rupnil ( ) said not to make them that big and commit more."}, {"post_id": 28620, "ts": "2026-07-14T23:47:14Z", "hours": 8.0197, "text": "StarWeb dev log #4 CROSS-PLATFORM SUPPORT AHHH!!! (BOTH MICRO SL.. WINDOWS AND LINUX! and yk it was working before on MacOS) The socket code was the first problem. Everything was written against BSD sockets, which Windows doesn’t speak. I pulled all of that behind a net.hpp wrapper: a socket_t type, a kInvalidSocket constant, and helpers like net::close, net::is_valid, and set_recv_timeout that pick BSD sockets or Winsock2 depending on platform. Small thing, but an invalid socket is -1 on POSIX and an unsigned INVALID_SOCKET on Windows, so you can’t just reuse the same sentinel value everywhere like I was doing before. Media playback was the other one. AVFoundation isn’t available outside macOS, so VideoPlayer now has two backends: AVFoundation on macOS, and a FFmpeg + miniaudio backend for Windows/Linux. Same play/pause/seek/volume API. Alongside that: a CMake build, a BUILDING.md with setup steps per platform, GitHub Actions building targets on push, and a LICENSE + third-party notices file, and that needed to be documented properly instead of just… not. (FFmpeg licensing is so confusing) Then: flexbox, and input types Once the cross-platform stuff was done, I went back to layout, which had been held together by manual cursor-position math since day one. I imported Yoga (the flexbox engine Meta built for React Native) and wired it into the renderer through a compute_flex_layout call, so display: flex, gap, and the flex-* properties are now working. The parser also handles text a lot better now. Before, it just dumped every raw character into text_content, so something like & showed up on the page as & instead of &. Now it decodes entities and splits text into its own #text nodes instead of gluing everything onto the parent tag. Forms are also better now because of new input types: name, min, max, step, checked, and gave the renderer form controls instead of the placeholder boxes, plus calendar and clock widgets for date/time inputs. Submitting one actually resets and collects values now. And we know what happens now…"}, {"post_id": 27454, "ts": "2026-07-13T01:05:41Z", "hours": 5.8397, "text": "StarWeb dev log #3 Finally made a media player! The fetcher now actually looks at what it downloaded instead of assuming everything’s HTML. It checks the Content-Type header first, falls back to the file extension if the server didn’t send one, and sorts the response into HTML, image, video, or audio. Anything that doesn’t match any of those (a plain .txt file, for instance) just gets rendered as text on the page instead of the browser trying to parse it and displaying nothing. Images and media get pulled down recursively too. The fetcher walks the page for <img> , <video> , <audio> , and <source> tags and fetches each one alongside the page itself, the same way it already did for stylesheets. Images go through stb_image , decoded from memory into an OpenGL texture. For video and audio tho, I built a small VideoPlayer wrapper around AVFoundation, so playback is currently macOS-only (sorry again, but I didn’t add support for Linux/Windows yet; just wait for next devlog, I promise). Fetched media gets cached to a folder on disk under a hashed filename, since AVFoundation wants an actual file to point at rather than a memory buffer. resolve_url was improved. It now knows moon:// defaults to 8090 and star:// to 8490 , so URLs don’t end up with a redundant :8090 attached onto every link. @Rupnil sorry man, I ran into issues ;-;"}, {"post_id": 26574, "ts": "2026-07-11T14:11:05Z", "hours": 8.9486, "text": "StarWeb dev log #2 The client could fetch static files but couldn’t render them. Starweb finally has a browser called Starmap ! The first version wasn’t much: a minimal parser splitting tags and attributes on whitespace, and a couple CSS properties. Only one page could be loaded at a time; it wasn’t much of a browser, but I wanted to at least render something. The whitespace-splitting parser didn’t last long. It broke when an attribute value contained a space, which style=\"...\" does constantly. So I rewrote it into a proper scanner that walks the tag character by character and actually respects quotes. That also made it easy to start picking up attributes I wasn’t tracking before: id , style (parsed into real properties instead of just stored as text), and type , value , and placeholder for form inputs. Nothing renders them yet, but the data’s there. CSS grew from a couple properties to something you can work with: padding and margin per side, width, height, border-width, border-color, font-size, display, each with its own inheritance rule so one style doesn’t just blindly overwrite another. Headings finally scale too; h1 down to h6 each get their own font-size multiplier instead of rendering at the same size as everything else. Pages could finally pull in external styling too, via <link rel=\"stylesheet\"> : the fetcher walks the parsed page for stylesheet links, resolves them against the current URL, and fetches each one as a secondary request before the CSS gets parsed. The layout change with the biggest visible impact was inline flow. Up to this point, every tag forced a new line, so a paragraph with a link in the middle of it rendered as three separate lines. Spans, links, buttons, and form controls now sit on the same line instead. <input> also stopped incorrectly behaving like a container element, since it shouldn’t be able to hold children. Then I added tabs. Each tab now owns its own URL, page, style, and fetch state. The window title and each tab’s label now follow the page’s <title> , falling back to the host and path if the page didn’t set one. I also swapped the default OS window frame for custom traffic-light controls (because I’m on a Mac and that’s how Chrome does it; sorry if it looks wrong on Linux or Windows, I haven’t tested yet). And also, resizing works correctly since the first version. By this point, the browser source had grown to 1700+ lines of code, holding everything: parsing, fetching, theme, and rendering. I split the browser into modules, leaving the main file responsible only for booting up and driving the UI loop. Woah, that was a lot, but I managed to do it in 3 days? idk how to count it because my sleep schedule is so cooked that I often worked at night and went to sleep at 4 am."}, {"post_id": 25531, "ts": "2026-07-09T20:59:40Z", "hours": 1.5122, "text": "StarWeb is my attempt at building an internet of my own. A custom protocol, a custom URL scheme, and a client and server that communicate using them.I put together STWP, my own protocol with request and response parsing, structured similarly to HTTP but built from scratch. The server runs multithreaded, serving files from a www folder, blocking path traversal attempts, and returning proper error codes when something’s missing or wrong. The client connects using its own URL format, moon://host:port/path, sends a request, and prints back whatever the server responds with. Essentially my own version of curl made for testing; I’m planning to make a browser later. Right now it only handles fetching static files."}]...
|
Title: Starweb by @mixidmb | Stardance
Devlogs:
S Title: Starweb by @mixidmb | Stardance
Devlogs:
StarWeb is my attempt at building an internet of my own. A custom protocol, a custom URL scheme, and a client and server that communicate using them.I put together STWP, my own protocol with request and response parsing, structured similarly to HTTP but built from scratch. The server runs multithreaded, serving files from a www folder, blocking path traversal attempts, and returning proper error codes when something’s missing or wrong. The client connects using its own URL format, moon://host:port/path, sends a request, and prints back whatever the server responds with. Essentially my own version of curl made for testing; I’m planning to make a browser later. Right now it only handles fetching static files.
StarWeb dev log #2 The client could fetch static files but couldn’t render them. Starweb finally has a browser called Starmap ! The first version wasn’t much: a minimal parser splitting tags and attributes on whitespace, and a couple CSS properties. Only one page could be loaded at a time; it wasn’t much of a browser, but I wanted to at least render something. The whitespace-splitting parser didn’t last long. It broke when an attribute value contained a space, which style="..." does constantly. So I rewrote it into a proper scanner that walks the tag character by character and actually respects quotes. That also made it easy to start picking up attributes I wasn’t tracking before: id , style (parsed into real properties instead of just stored as text), and type , value , and placeholder for form inputs. Nothing renders them yet, but the data’s there. CSS grew from a couple properties to something you can work with: padding and margin per side, width, height, border-width, border-color, font-size, display, each with its own inheritance rule so one style doesn’t just blindly overwrite another. Headings finally scale too; h1 down to h6 each get their own font-size multiplier instead of rendering at the same size as everything else. Pages could finally pull in external styling too, via <link rel="stylesheet"> : the fetcher walks the parsed page for stylesheet links, resolves them against the current URL, and fetches each one as a secondary request before the CSS gets parsed. The layout change with the biggest visible impact was inline flow. Up to this point, every tag forced a new line, so a paragraph with a link in the middle of it rendered as three separate lines. Spans, links, buttons, and form controls now sit on the same line instead. <input> also stopped incorrectly behaving like a container element, since it shouldn’t be able to hold children. Then I added tabs. Each tab now owns its own URL, page, style, and fetch state. The window title and each tab’s label now follow the page’s <title> , falling back to the host and path if the page didn’t set one. I also swapped the default OS window frame for custom traffic-light controls (because I’m on a Mac and that’s how Chrome does it; sorry if it looks wrong on Linux or Windows, I haven’t tested yet). And also, resizing works correctly since the first version. By this point, the browser source had grown to 1700+ lines of code, holding everything: parsing, fetching, theme, and rendering. I split the browser into modules, leaving the main file responsible only for booting up and driving the UI loop. Woah, that was a lot, but I managed to do it in 3 days? idk how to count it because my sleep schedule is so cooked that I often worked at night and went to sleep at 4 am.
StarWeb dev log #3 Finally made a media player! The fetcher now actually looks at what it downloaded instead of assuming everything’s HTML. It checks the Content-Type header first, falls back to the file extension if the server didn’t send one, and sorts the response into HTML, image, video, or audio. Anything that doesn’t match any of those (a plain .txt file, for instance) just gets rendered as text on the page instead of the browser trying to parse it and displaying nothing. Images and media get pulled down recursively too. The fetcher walks the page for <img> , <video> , <audio> , and <source> tags and fetches each one alongside the page itself, the same way it already did for stylesheets. Images go through stb_image , decoded from memory into an OpenGL texture. For video and audio tho, I built a small VideoPlayer wrapper around AVFoundation, so playback is currently macOS-only (sorry again, but I didn’t add support for Linux/Windows yet; just wait for next devlog, I promise). Fetched media gets cached to a folder on disk under a hashed filename, since AVFoundation wants an actual file to point at rather than a memory buffer. resolve_url was improved. It now knows moon:// defaults to 8090 and star:// to 8490 , so URLs don’t end up with a redundant :8090 attached onto every link. @Rupnil sorry man, I ran into issues ;-;
StarWeb dev log #4 CROSS-PLATFORM SUPPORT AHHH!!! (BOTH MICRO SL.. WINDOWS AND LINUX! and yk it was working before on MacOS) The socket code was the first problem. Everything was written against BSD sockets, which Windows doesn’t speak. I pulled all of that behind a net.hpp wrapper: a socket_t type, a kInvalidSocket constant, and helpers like net::close, net::is_valid, and set_recv_timeout that pick BSD sockets or Winsock2 depending on platform. Small thing, but an invalid socket is -1 on POSIX and an unsigned INVALID_SOCKET on Windows, so you can’t just reuse the same sentinel value everywhere like I was doing before. Media playback was the other one. AVFoundation isn’t available outside macOS, so VideoPlayer now has two backends: AVFoundation on macOS, and a FFmpeg + miniaudio backend for Windows/Linux. Same play/pause/seek/volume API. Alongside that: a CMake build, a BUILDING.md with setup steps per platform, GitHub Actions building targets on push, and a LICENSE + third-party notices file, and that needed to be documented properly instead of just… not. (FFmpeg licensing is so confusing) Then: flexbox, and input types Once the cross-platform stuff was done, I went back to layout, which had been held together by manual cursor-position math since day one. I imported Yoga (the flexbox engine Meta built for React Native) and wired it into the renderer through a compute_flex_layout call, so display: flex, gap, and the flex-* properties are now working. The parser also handles text a lot better now. Before, it just dumped every raw character into text_content, so something like & showed up on the page as & instead of &. Now it decodes entities and splits text into its own #text nodes instead of gluing everything onto the parent tag. Forms are also better now because of new input types: name, min, max, step, checked, and gave the renderer form controls instead of the placeholder boxes, plus calendar and clock widgets for date/time inputs. Submitting one actually resets and collects values now. And we know what happens now…
StarWeb dev log #5 Lua support! Every tab gets its own ScriptEngine , a sandboxed Lua 5.4 interpreter. A custom allocator caps its memory, an instruction hook kills it when it runs past its time budget, and require , dofile , and loadfile don’t exist in there. It’s untrusted code from whatever page you loaded. Scripts get a DOM API: getElementById , querySelector , innerText , get / setAttribute , addEventListener , console.log , alert , setTimeout / setInterval , requestAnimationFrame . There’s a location object too, so scripts can navigate, but only to moon:// URLs. Yes, there is <canvas> . getContext("2d") gives you fillRect , paths, arcs, fillText , but scripts never touch the screen directly; every call gets recorded into a list of CanvasOp s and the renderer draws the list. To test all of it, I wrote a raycaster ( www/game.lua ), a small maze you can walk around in, running entirely as a page script. external scripts and keyboard input <script src="..."> works, not just inline scripts. The fetcher downloads them so the engine sees them in document order. Keyboard input works too; keys get polled from GLFW and sent to the active tab, so document.addEventListener("keydown", ...) does something. That’s how the raycaster gets its controls. The main loop also stopped redrawing at 60fps when nothing’s happening. It sleeps until something needs a frame: a fetch, a playing video, a pending timer, or requestAnimationFrame . Good for the battery. (My MacBook 2015 was on fire when the browser ran. That’s how I noticed lol) Also, from now on I will be posting more devlogs because im done with the core stuff. Rupnil ( ) said not to make them that big and commit more.
StarWeb dev log #6 StarWeb has secure connections now: star:// . star:// is to moon:// what https is to http : same STWP messages; the transport underneath is just TLS 1.3 (OpenSSL 3) instead of plaintext TCP. Plaintext moon:// stays on port 8090, encrypted star:// runs on 8490, and the server serves both at once. There’s a tools/make_certs.sh that spins up a local root CA and a server cert so you can test it. The CA only signs localhost , .local / .star , and private IPs ( 10.x , 192.168.x , etc.), so it works on your LAN but not the public internet. (I it will be public after i make DNS) The address bar got a lock icon. Click it, and you get a cert info popup: who issued it, who it’s for, that kind of thing. If the handshake fails, verification fails, cert’s self-signed, expired, wrong host, you get a full-page interstitial instead of the page, same as a real browser yells at you. the security rules A star:// page can’t pull in moon:// content. Mixed content is blocked; no loading plaintext resources into a page you’re being told is secure. Downgrades are blocked too, and stricter than the normal web; here, a script can’t navigate you from star:// to moon:// . You can still type a moon:// URL yourself; that’s your call, but a page can’t quietly drop you off TLS. TLS also enforces ALPN and checks the hostname, and there’s a session resumption cache so reconnecting doesn’t redo the whole handshake every time. Also fixed URL parsing to handle IPv6 addresses in brackets ( [::1] ), which it just choked on before.
StarWeb dev log #7 You can write StarWeb backends in Python now. Everything so far has been C++. Writing a page that did anything meant static files or a Lua script in the browser. So there’s now a starweb Python package that speaks STWP, in two halves. The server half looks like Flask. Make an App , decorate functions with @app.route("/api/time") , return a dict, and it goes out as JSON, or a Response for control over status and headers. Routes take params ( /api/greet/<name> ), the request has a query dict, and app.mount_static("/", "www") serves files with routes winning over static. app.run(scheme="both") hosts moon:// and star:// at once, thread per connection, same as the C++ server. The client half looks like requests. starweb.get("moon://localhost/") , .post(...) , a Session to reuse a connection, and TLS for star:// with each failure getting its own exception ( TLSVerificationError , MixedContentError , ALPNError ). it only speaks STWP The interesting part is what it refuses. Send the server an HTTP request line, and it answers 505 and hangs up; curl and a browser can’t wander in by accident. The client trusts only the StarWeb root CA, never the system roots, and it’s pinned to TLS 1.3 and nothing else. ALPN is required: no stwp/1.0 , connection dropped. the CLI starweb get moon://localhost/index.html fetches a URL, -v for headers and TLS info. starweb serve app.py runs a file defining an App , with --scheme , --no-tls , --log . curl and a dev server in one command. It’s a proper pip package too: README, license, pyproject.toml , pip install starweb and you get a starweb command. And there are tests: interop against the C++ server, URL and message parsing, schemes, isolation, which caught a couple of parser mismatches between the two.
Starweb dev log #8 Page scripts can fetch() now. fetch("/api/time", function(err, res) ... end) runs on a worker thread and calls you back when it’s done, so the page never freezes. You get res.status , res.ok , res.body , res.headers , and res:json() . POST works too: fetch("/api/echo", { method = "POST", json = { hi = "there" } }, cb) . There’s a json global with it ( json.encode / json.decode ). Limits: 6 fetches at a time, 1MB request body, 8MB response, caps on headers, URL length, and JSON depth. Cross-origin requests are CORS-gated by browsers; a fetch to another host only returns a body if it sends Access-Control-Allow-Origin . The Python server got a per-route cors= option to match. Also refactored the fetcher: one perform_request with RequestOptions (method, headers, body, timeouts, max size), and perform_fetch is a thin wrapper for navigations on top. Scripted fetch and the address bar share code now instead of two separate socket loops.
Starweb dev log #9 Media streams now instead of downloading the whole file first. A big MP4 used to sit there until every byte landed. Now there’s a MediaSource : a seekable view of the remote file that fills in as it’s read, so the decoder starts on the first megabyte while the rest is still downloading. It runs on Range requests. The server advertises Accept-Ranges: bytes and answers bytes=a-b , bytes=a- , or bytes=-n (trailing bytes, how a player finds an MP4’s moov atom) with 206 . Bad or multi-range requests get 416 . It streams the file out in chunks rather than loading it into memory, so the server side is cheap too. On the browser, chunks land in a sparse cache file in 64KB pieces, and a read only blocks on the chunks it touches. A .ranges sidecar tracks what’s present; once it’s all there, the file is the cache entry. Seeking doesn’t wait behind the sequential download; hint_seek steers the prefetcher to where you jumped. Both backends got wired in: FFmpeg through custom IO, macOS through AVAssetResourceLoader . Cache pruning counts real bytes on disk now and cleans up the .ranges sidecars, and there are range tests on the Python side ( bytes=a-b , EOF, suffix, 416 , clamping).
Starweb dev log #10 Starweb has domains now. There’s .web , with a DNS behind it. StarDNS (name is temporary) is an authoritative server for the .web zone. It answers over UDP, falls back to TCP when a reply won’t fit, and reads records out of MongoDB. Three parts in one process: the resolver, a panel to manage names, and a CA that issues star:// certs. the panel Sign in, and you get three domains, each a single label under .web . Records are A , AAAA , CNAME , TXT with a TTL from 60 to 86400. The rules a resolver relies on are enforced on the way in: a CNAME can’t share a name with another record or sit at the apex. @ is the domain itself, *.dev is a wildcard, and a CNAME target with no dot is relative. It’s served with the starweb package, so you browse it in Starmap like any page. Every action is also a JSON route, so it’s scriptable from starweb post . certificates “Issue certificate” makes a P-256 leaf covering mysite.web and *.mysite.web , signed by the StarWeb root, valid 825 days. Stored in Mongo and written to dns/issued/ ; the key never touches the database. The root is name-constrained to .web now, so it can’t issue for a public name; ca.issue("www.google.com") fails its own verify, and a test holds it there. resolving The browser and client resolve .web themselves. A host in the zone gets asked straight to StarDNS over UDP ( src/common/resolver.hpp ), never getaddrinfo , which would leak the lookup to a public DNS. No fallback: if StarDNS can’t answer, the load fails instead of quietly asking the public resolver. Anything that isn’t .web still goes to the system resolver. It chases CNAMEs, queries A and AAAA separately, and caches by TTL so a page’s subresources cost one lookup. Point it elsewhere with STARWEB_DNS , or STARWEB_DNS=off to fall back. Next is the look of the website.
Starweb devlog #11 Nebula login page design. I don’t have much to talk about today, so enjoy the video.
Starweb dev log #12 I started redesigning the panel. Signed in, you land on a sidebar with tabs (home, domains, analytics), a search bar, and a home page. (Cloudflare copy ik lol) The sidebar icons are Lucide SVGs. Those are drawn on a 24x24 grid and use way more of the SVG path language than my login art did: relative commands, H / V , arcs, closepath, plus <circle> elements. The browser has no SVG parser yet (but ig it’s unavoidable at this point), so I wrote a script ( shapes.py ) that reads each icon once and flattens it into plain points, arcs, and all. Those points get baked straight into the page’s Lua as a table, so the page itself is just normal HTML and Lua, no different from any other page, and the script just loops over the points and draws them. Rendering also looks sharper now. Layout and drawing account for the framebuffer scale, so the vector art doesn’t go blurry on a hi-DPI window anymore.
Starweb dev log #13 Added analytics and worked on the domains page. The resolver bumps a counter every time it answers a lookup: one document per domain per day, not per query. It’s best-effort: if the analytics write fails, the answer still goes out. Missing days are zero-filled, so a new domain shows a flat line instead of a gap. That feeds two chart types in Lua, chartBars and chartLine , just canvas: fillRect bars or a stroked polyline. Zero draws nothing, and only a real value gets a 2px floor. The home page gets one combined trend line across every domain, the domains list gets a sparkline per row. Also fixed a flex-grow input because it didn’t fill its row width. Inputs and textareas now stretch to match, so form rows line up.
Starweb dev log #14 Analytics got a range picker, and the drawing underneath it got a lot cheaper to run. The panel graphs now go from 1h up to 1y, not just a fixed 14 days. That needed a second counter: stats_min , one document per domain per minute, which only exists to answer the sub-day windows and ages out on a TTL index. The old daily stats collection stays forever so the all-time total is still exact. Past a month the buckets widen to weeks then 30-day chunks, since 180 daily points would just read as a smear at chart width. The nebula background got refactored for speed: prep() runs once per canvas resize and does all the expensive math, square roots, atan2 , walking every line segment, into a flat array; lit() runs per frame and just reads that array plus whatever actually changes frame to frame (the shine position, the cog’s rotation). Same picture, way less work per frame. Hex color parsing got a fast path too, since a canvas setting fillStyle per dot was hitting the full color parser thousands of times a frame for the one form it ever uses. Canvas itself grew a few things: fillRect / strokeRect take an optional radius now, measureText reads the actual font the page pushed instead of the UI default, and hoverX / hoverY are readable off a canvas element. The ctx method lookup also switched from a chain of strcmp to a real table, since a heavy canvas loop calls into it constantly. requestAnimationFrame self-paces now. A callback that runs long gets a gap after it sized to what it just cost, capped at 500ms, so one expensive canvas can’t eat the whole frame budget. It also only fires for the visible tab and stops while the window’s minimized; timers and fetches keep going regardless, same as a background tab in a real browser.
Starweb dev log #15 Added live search and SVG rendering. Type in the sidebar or the home search, and a dropdown fills in as you go. That needed a new input event for page scripts, they only got click before. Queries are percent-encoded before they hit the URL, with a small urlenc() since this runtime has no encodeURIComponent . Also added recent pages on the home screen, capped at 3, deduped, ordered so two clicks in the same instant land right.
Starweb dev log #16 DevTools! F12 or Cmd/Ctrl+Shift+I opens a dock on the right side of the page. Elements works: a picker button lets you click something on the page to select it, or walk the DOM tree directly. Selecting a node shows its computed styles and box model, with real layout padding rather than just the CSS value. Console works too. Whatever you type evaluates in that tab’s own Lua engine, with history on up/down. Network, Sources, and Metrics are just tabs for now, not built yet. Im going to be working on design now
Starweb dev log #17 Restyled the browser to match Nebula, and gave it real icons. The toolbar and tab icons used to be hand-drawn with ImGui lines. Now they’re Lucide SVGs, rasterized once and tinted. Layout used to be random numbers everywhere; now it’s all one Trim namespace. Colors follow one ramp: dim, then mid, then bright when focused.
Starweb dev log #18 (woah didn’t devlog for a while) Network tab and DevTools got restyled to match the rest. Every request now gets timed in stages: resolve, connect, TLS, send, wait, download, each stamped as it happens inside perform_request . The panel draws that as a bar per stage, plus headers, response preview, and a security tab with the TLS info for that request. Then the devtools were redesigned to match the browser style from the last devlog.
Starweb dev log #19 Sources panel. It lists everything the page fetched, grouped into: Document, Scripts, Stylesheets, Images, Media, Fonts. Text files have a viewer, wrap toggle, find-in-file, and line numbers. Images show the texture. Media points to the page’s own player rather than opening a second stream, since a URL only has one range cache.
Starweb dev log #20 Zoom feature. Ctrl/Cmd +/-/0, or Ctrl+scroll over the page. Goes through steps from 25% to 300%, same as a real browser, with a small pill in the corner showing the percentage and a Reset button that fades when not zooming anymore.
Starweb dev log #21 Pages can save data now: localStorage , per origin. Origin is scheme, host, and port, so moon:// and star:// don’t share a store. getItem / setItem / removeItem / clear / key , indexing ( localStorage[k] = v ), .length . Capped at 4096 keys, 5MB per origin. Sources in DevTools has a Storage group, with Delete and Clear buttons.
Starweb dev log #22 Context menu, the three-dot button, has New Tab, History, Zoom, and Clear History as of right now. History saves to disk like localStorage; icons are cached per origin. The menu shows the last 5 visits (I will make a page where you can browse more)....
|
1792900455.1430833
|
1793764455.1430833
|
|
21782
|
Prep App by @teteos | Stardance
|
teteos
|
0
|
97.76
|
0
|
[]
|
[{"post_id": 38856, "ts": "202 [{"post_id": 38856, "ts": "2026-08-01T12:49:09Z", "hours": 13.135, "text": "#devlog 5 :) Heyy!! everyone So, I’m building a context aware ai SAT app with flutter and dart with firebase and yea [I been so lost in schoolwork and got a fever n all so i wasn’t quite active.] Major changes i did : 1. For setup screen ( yea i’m still and still lost there): Last time, we had choosing a language in first step then answer some questions for the app to know u better but but it was only in english right like u choose the lanuage and the questions come in jus english and the Bottom Navigation Bar items where only converted into ur language buttttt i thought that why not covert the whole options and questions in ur language soooooo now tutorio converts IN 27 LANGUAGES the sec u choose the language ( i udpated 27 json files) and even greets u and motivates u in ur own language in the homescreen 2. Homescreen ( yea smthg new): yea i finally did smthg for the homescreen Now we 4 major sections home,leaderboard,test,profile and the homescreen greets u in ur language and has the top score board so when i have real users the app will show who got the highest test score in that 24 HOURS and then we have 4 modules and now ta i have made only outer screen ( i have add all course inside each modules and chapterwise test and have gemini api give u answers acc to ur ed system and learning style) So, thats it i have 27 LANGUAGE converting and a decent homescreen and yea Errors 😭:Cloudfirestore : Yea, I was running my app then suddenly when i choose a language it hit a error and boom everything was red and yellow warnings. I was so afraid and was thinking maybe i forgot to add a language in maindart or hsd and i was so freaked out and then i started to redo i activities then i realized i hadnt done billing in firestore when a created a database (i’m 15 , so no credit cards) yea i searched up for options then learned about storing locally and used sharedpreferences in flutter to keep everything running locally. Thanks for catching up and i’ll try to be more regular"}, {"post_id": 31308, "ts": "2026-07-19T16:35:23Z", "hours": 4.9789, "text": "Devlog #5 — Splash Screen + Setup Screen (˶ᵔᗜᵔ˶)ノ゙ Hello everyone!! This is my last devlog for that 80 hrs ( busy with school stuffs) . BEfore it had only 15 language in a big dart file now i did it better and debugged for 3 hrs and had like 27 json files to make it devlog presentable .This one covers the splash screen and the setup screen. The Splash Screen the splash screen is the first thing you see when you open Tutorio. The Tutorio logo fades in smoothly on a white background over 1.5 seconds, with a “LOADING…” label and a blue progress bar fading in underneath. Stays for 3 seconds then moves to login. I wrapped the progress bar in a ClipRRect to give it rounded edges instead of the ugly default sharp corners, and made sure to check mounted before navigating so it doesn’t crash if the user somehow exits early. The Setup Screen After login and signup, new users hit the setup screen before accessing anything else. This is genuinely the most important part of Tutorio’s whole concept — because the app is built specifically for international students, I need to know who you are before the AI can actually help you properly. The screen is split into two steps using a PageView with NeverScrollableScrollPhysics so users can only move forward using the button, not by swiping. Step 2 captures the student profile — grade, school system , home country, learning style, daily study time, and target SAT score. All six required. Once done it saves to Firestore under the user’s UID with setupComplete: true so this screen never appears again. Step 1 is where it got interesting. I needed to support 28 languages with their flags in a grid — Arabic, Bengali, Hindi, Nepali, Mandarin, Vietnamese, Turkish and more. My first instinct was to just keep everything in a giant Dart map directly in the code, something like: dartconst Map<String, Map<String, String» localizedValues = { ‘en’: {‘welcome’: ‘Welcome to Tutorio!’}, ‘ar’: {‘welcome’: ‘مرحباً بك في Tutorio!’}, }; And honestly for like 2-3 languages this works fine. Zero setup, no async loading, VS Code catches typos instantly. But the second I scaled to 27 languages it completely fell apart. The Dart files were getting thousands of lines long and impossible to read. If I wanted someone to fix a typo in Vietnamese or Turkish I’d have to hand them a raw .dart code file which is both a security risk and a syntax disaster waiting to happen. And worst of all, Flutter would load every single language’s strings into RAM at launch even though the user only needs one language active at a time. Complete waste. So I switched everything to external JSON files — en.json, ar.json, ne.json, one per language — all sitting inside assets/translations/. Then integrated the easy_localization package which lets me just call .tr() on any text widget anywhere in the app: dartText(‘welcome_msg’.tr()) The package dynamically opens the correct JSON file based on whatever language the user picked in setup, extracts the right string, and swaps it in on the fly. The Dart code went back to being clean UI logic with zero hardcoded text sitting in it. The best part — if I want to add language number 29, I don’t touch a single line of Flutter code. I just drop a new .json file into the translations folder and it works. Bugs I hit along the way 😭 Broken Imports: Restructuring into subfolders broke every import path reference and I had to fix them all manually. Not fun. Cascade Failure: An empty placeholder .dart file caused a domino effect and broke 4 other working files at once. Took forever to figure out what happened lol. Deprecation Warnings: Had to swap every .withOpacity() call across the project for the new .withValues(alpha:) method. Anyway that’s everything!! Next devlog covers the home screen and AI question engine. See you then (˶ᵔᗜᵔ˶) ✧"}, {"post_id": 26665, "ts": "2026-07-11T16:38:52Z", "hours": 0.3756, "text": "(#devlog4) Hello everyone(˶ᵔᗜᵔ˶)ノ゙, Welcome to Devlog #04 of my SAT Prep app of covering wot i did Hope you all are doing great. So right after finishing the log-in page, I jumped straight into getting the signup screen fully sorted out. Just like before, I made sure it connects smoothly to the home screen and lets you quickly tap back to the login page if you already have an account. I kept the exact same three options here too: full name with email/password, phone number signup, and a quick Google link. Since I had already gone through the absolute ringer getting Firebase and the whole ./gradlew signingReport SHA key situation set up for the phone auth on the login side, getting it running here wasn’t as brutal… but ugh, making sure the new account creation logic passed the user’s name correctly to the Firebase database so it actually updates their profile still took some annoying tweaking under the hood ∘ ∘ ∘ ( °ヮ° )I also cleaned up the styling here to match the new look completely! I dumped the old circular buttons and that top dark gap, changing it to the clean, edge-to-edge white layout. The fields and rectangular social buttons now stretch all the way across the screen beautifully ദ്ദി(˵ •̀ ᴗ - ˵ ) ✧It feels way less cramped now, and everything aligns perfectly from the top to the bottom of the phone screen. Having both screens look identical makes the whole app feel like a real product now. So, yea and has like that asking ur education system so that the ai explanation and learning environment system will know and help u better. I’ll upload a read me on monday and this is my sign up screen. Thank You all so much for reading. Have a nice day =) ( i also learned we can upload more than one ss) :)"}, {"post_id": 26632, "ts": "2026-07-11T15:49:50Z", "hours": 0.5253, "text": "(#devlog3) I’m covering wot i did So yeah, for the login screen, I finally got it all hooked up and navigating properly to the home screen and the signup page. For the actual login options, I went with email/password, phone number, and Google sign-in. Getting all of that working with Firebase was honestly a massive headache, especially the phone auth side of things. It was tripping up so much that I literally had to rip it all out at one point, start over, and re-add it from scratch.To finally get it to cooperate, I had to create a separate auth_service.dart file to handle the logic and open up the terminal to run ./gradlew signingReport. That gave me the SHA keys I needed to paste into the Firebase console so the SMS codes would actually send. Design-wise, I wasn’t totally feeling the color choices and layout at first. It had these circular buttons and after that i changed to rectangle and i am not still sure with colour combo some times i want like classic and sometimes bubbly all of the options work by firebase ( since i using all google like gemini api,firebase n alll so i use firebase)"}, {"post_id": 26561, "ts": "2026-07-11T13:38:47Z", "hours": 67.5394, "text": "bruhhhh!!! its my first event so I didn’t know that we have to write devlog ( my first devlog had 1 view so i didnt upload other devlog i thought i’ll cover at end) so dumb okie now i cover wot ever i did in 5 devlogs okie this is my 1st one (#devlog2) soo yea after i set my flutter bg and all i created a new file login screen and i spent alot of time first selecting wot wot to keep like first i kept options: facebook,google,github,email and phone but i dont use fb yea so I was about to create one (for meta developer acc and testing) but i thought maybe i shouldnt add fb cuz yk young people rarely use it and i also removed github cuz there is rarely one in a sat app, so yea at last i kept phone,email and google and look this is my finalized app logo and in next devlog i’ll tell wot i finalized in my log in screen ( in next 15 min)"}, {"post_id": 13231, "ts": "2026-06-21T17:42:32Z", "hours": 11.2083, "text": "Devlog #1 Heyyy!!! i’m sweta and i’m making a SAT prep app for international students. So, most prep apps assume cultural context American students already have — idioms, references, essay phrasing. International students often lose points not from weak math, but from never having heard a phrase like “the writing was compelling.” This app gives AI-generated explanations that adapt to the student’s education system and English level. Stack: Flutter (one app for Android/iOS/web), Dart (Flutter’s language), Firebase (handles accounts/data, no server needed), Gemini API (generates explanations). Installing Flutter winget didn’t have it, so I cloned it from GitHub: git clone https://github.com/flutter/flutter.git C:\\flutter Added it to PATH so the terminal recognizes the flutter command: $env:Path += “;C:\\flutter\\bin” Ran flutter doctor to check the setup. VS Code + Android SDK Installed the Flutter extension (pulls in Dart too) — had to restart VS Code before commands appeared. Installed Android Studio only to get the Android SDK in the background; all real coding happens in VS Code. Fixed missing command-line tools via Android Studio’s SDK Manager, and accepted licenses with flutter doctor –android-licenses. Skipping the emulator Emulators eat RAM my laptop doesn’t have spare. Testing on my real phone over USB instead — enabled Developer Options + USB debugging, allowed the popup, confirmed detection with flutter devices. First run flutter create sat_prep_app cd sat_prep_app flutter run create makes a starter project with a demo app built in. run compiles and installs it on the connected phone. Slow first build, but it worked — proof the whole chain (Flutter → SDK → phone) connected properly. Firebase setup Created a free Firebase project (no billing), registered an Android app, placed the generated google-services.json config into android/app/. Added packages: flutter pub add firebase_core flutter pub add firebase_auth flutter pub add google_sign_in pub add installs pre-written code instead of writing it myself. firebase_core is required for any Firebase feature, firebase_auth handles sign up/login, google_sign_in adds Google login. Linking Flutter to Firebase dart pub global activate flutterfire_cli npm install -g firebase-tools firebase login flutterfire configure The FlutterFire CLI needed the separate official Firebase CLI too. The last command generated firebase_options.dart, auto-configuring Android, iOS, web, macOS, and Windows at once. Making the app use it Added Firebase initialization to the app’s startup code, swapped the demo app for a placeholder “Sign Up Screen Coming Soon” screen. Ran it again — showed up cleanly, no crashes, confirming Firebase is wired in. What’s next Real Sign Up and Login screens, connected to Firebase Authentication, then (country, education system, English level, SAT goals) (i’m using my phone not a emulator)"}]...
|
Title: Prep App by @teteos | Stardance
Devlogs:
D Title: Prep App by @teteos | Stardance
Devlogs:
Devlog #1 Heyyy!!! i’m sweta and i’m making a SAT prep app for international students. So, most prep apps assume cultural context American students already have — idioms, references, essay phrasing. International students often lose points not from weak math, but from never having heard a phrase like “the writing was compelling.” This app gives AI-generated explanations that adapt to the student’s education system and English level. Stack: Flutter (one app for Android/iOS/web), Dart (Flutter’s language), Firebase (handles accounts/data, no server needed), Gemini API (generates explanations). Installing Flutter winget didn’t have it, so I cloned it from GitHub: git clone https://github.com/flutter/flutter.git C:\flutter Added it to PATH so the terminal recognizes the flutter command: $env:Path += “;C:\flutter\bin” Ran flutter doctor to check the setup. VS Code + Android SDK Installed the Flutter extension (pulls in Dart too) — had to restart VS Code before commands appeared. Installed Android Studio only to get the Android SDK in the background; all real coding happens in VS Code. Fixed missing command-line tools via Android Studio’s SDK Manager, and accepted licenses with flutter doctor –android-licenses. Skipping the emulator Emulators eat RAM my laptop doesn’t have spare. Testing on my real phone over USB instead — enabled Developer Options + USB debugging, allowed the popup, confirmed detection with flutter devices. First run flutter create sat_prep_app cd sat_prep_app flutter run create makes a starter project with a demo app built in. run compiles and installs it on the connected phone. Slow first build, but it worked — proof the whole chain (Flutter → SDK → phone) connected properly. Firebase setup Created a free Firebase project (no billing), registered an Android app, placed the generated google-services.json config into android/app/. Added packages: flutter pub add firebase_core flutter pub add firebase_auth flutter pub add google_sign_in pub add installs pre-written code instead of writing it myself. firebase_core is required for any Firebase feature, firebase_auth handles sign up/login, google_sign_in adds Google login. Linking Flutter to Firebase dart pub global activate flutterfire_cli npm install -g firebase-tools firebase login flutterfire configure The FlutterFire CLI needed the separate official Firebase CLI too. The last command generated firebase_options.dart, auto-configuring Android, iOS, web, macOS, and Windows at once. Making the app use it Added Firebase initialization to the app’s startup code, swapped the demo app for a placeholder “Sign Up Screen Coming Soon” screen. Ran it again — showed up cleanly, no crashes, confirming Firebase is wired in. What’s next Real Sign Up and Login screens, connected to Firebase Authentication, then (country, education system, English level, SAT goals) (i’m using my phone not a emulator)
bruhhhh!!! its my first event so I didn’t know that we have to write devlog ( my first devlog had 1 view so i didnt upload other devlog i thought i’ll cover at end) so dumb okie now i cover wot ever i did in 5 devlogs okie this is my 1st one (#devlog2) soo yea after i set my flutter bg and all i created a new file login screen and i spent alot of time first selecting wot wot to keep like first i kept options: facebook,google,github,email and phone but i dont use fb yea so I was about to create one (for meta developer acc and testing) but i thought maybe i shouldnt add fb cuz yk young people rarely use it and i also removed github cuz there is rarely one in a sat app, so yea at last i kept phone,email and google and look this is my finalized app logo and in next devlog i’ll tell wot i finalized in my log in screen ( in next 15 min)
(#devlog3) I’m covering wot i did So yeah, for the login screen, I finally got it all hooked up and navigating properly to the home screen and the signup page. For the actual login options, I went with email/password, phone number, and Google sign-in. Getting all of that working with Firebase was honestly a massive headache, especially the phone auth side of things. It was tripping up so much that I literally had to rip it all out at one point, start over, and re-add it from scratch.To finally get it to cooperate, I had to create a separate auth_service.dart file to handle the logic and open up the terminal to run ./gradlew signingReport. That gave me the SHA keys I needed to paste into the Firebase console so the SMS codes would actually send. Design-wise, I wasn’t totally feeling the color choices and layout at first. It had these circular buttons and after that i changed to rectangle and i am not still sure with colour combo some times i want like classic and sometimes bubbly all of the options work by firebase ( since i using all google like gemini api,firebase n alll so i use firebase)
(#devlog4) Hello everyone(˶ᵔᗜᵔ˶)ノ゙, Welcome to Devlog #04 of my SAT Prep app of covering wot i did Hope you all are doing great. So right after finishing the log-in page, I jumped straight into getting the signup screen fully sorted out. Just like before, I made sure it connects smoothly to the home screen and lets you quickly tap back to the login page if you already have an account. I kept the exact same three options here too: full name with email/password, phone number signup, and a quick Google link. Since I had already gone through the absolute ringer getting Firebase and the whole ./gradlew signingReport SHA key situation set up for the phone auth on the login side, getting it running here wasn’t as brutal… but ugh, making sure the new account creation logic passed the user’s name correctly to the Firebase database so it actually updates their profile still took some annoying tweaking under the hood ∘ ∘ ∘ ( °ヮ° )I also cleaned up the styling here to match the new look completely! I dumped the old circular buttons and that top dark gap, changing it to the clean, edge-to-edge white layout. The fields and rectangular social buttons now stretch all the way across the screen beautifully ദ്ദി(˵ •̀ ᴗ - ˵ ) ✧It feels way less cramped now, and everything aligns perfectly from the top to the bottom of the phone screen. Having both screens look identical makes the whole app feel like a real product now. So, yea and has like that asking ur education system so that the ai explanation and learning environment system will know and help u better. I’ll upload a read me on monday and this is my sign up screen. Thank You all so much for reading. Have a nice day =) ( i also learned we can upload more than one ss) :)
Devlog #5 — Splash Screen + Setup Screen (˶ᵔᗜᵔ˶)ノ゙ Hello everyone!! This is my last devlog for that 80 hrs ( busy with school stuffs) . BEfore it had only 15 language in a big dart file now i did it better and debugged for 3 hrs and had like 27 json files to make it devlog presentable .This one covers the splash screen and the setup screen. The Splash Screen the splash screen is the first thing you see when you open Tutorio. The Tutorio logo fades in smoothly on a white background over 1.5 seconds, with a “LOADING…” label and a blue progress bar fading in underneath. Stays for 3 seconds then moves to login. I wrapped the progress bar in a ClipRRect to give it rounded edges instead of the ugly default sharp corners, and made sure to check mounted before navigating so it doesn’t crash if the user somehow exits early. The Setup Screen After login and signup, new users hit the setup screen before accessing anything else. This is genuinely the most important part of Tutorio’s whole concept — because the app is built specifically for international students, I need to know who you are before the AI can actually help you properly. The screen is split into two steps using a PageView with NeverScrollableScrollPhysics so users can only move forward using the button, not by swiping. Step 2 captures the student profile — grade, school system , home country, learning style, daily study time, and target SAT score. All six required. Once done it saves to Firestore under the user’s UID with setupComplete: true so this screen never appears again. Step 1 is where it got interesting. I needed to support 28 languages with their flags in a grid — Arabic, Bengali, Hindi, Nepali, Mandarin, Vietnamese, Turkish and more. My first instinct was to just keep everything in a giant Dart map directly in the code, something like: dartconst Map<String, Map<String, String» localizedValues = { ‘en’: {‘welcome’: ‘Welcome to Tutorio!’}, ‘ar’: {‘welcome’: ‘مرحباً بك في Tutorio!’}, }; And honestly for like 2-3 languages this works fine. Zero setup, no async loading, VS Code catches typos instantly. But the second I scaled to 27 languages it completely fell apart. The Dart files were getting thousands of lines long and impossible to read. If I wanted someone to fix a typo in Vietnamese or Turkish I’d have to hand them a raw .dart code file which is both a security risk and a syntax disaster waiting to happen. And worst of all, Flutter would load every single language’s strings into RAM at launch even though the user only needs one language active at a time. Complete waste. So I switched everything to external JSON files — en.json, ar.json, ne.json, one per language — all sitting inside assets/translations/. Then integrated the easy_localization package which lets me just call .tr() on any text widget anywhere in the app: dartText(‘welcome_msg’.tr()) The package dynamically opens the correct JSON file based on whatever language the user picked in setup, extracts the right string, and swaps it in on the fly. The Dart code went back to being clean UI logic with zero hardcoded text sitting in it. The best part — if I want to add language number 29, I don’t touch a single line of Flutter code. I just drop a new .json file into the translations folder and it works. Bugs I hit along the way 😭 Broken Imports: Restructuring into subfolders broke every import path reference and I had to fix them all manually. Not fun. Cascade Failure: An empty placeholder .dart file caused a domino effect and broke 4 other working files at once. Took forever to figure out what happened lol. Deprecation Warnings: Had to swap every .withOpacity() call across the project for the new .withValues(alpha:) method. Anyway that’s everything!! Next devlog covers the home screen and AI question engine. See you then (˶ᵔᗜᵔ˶) ✧
#devlog 5 :) Heyy!! everyone So, I’m building a context aware ai SAT app with flutter and dart with firebase and yea [I been so lost in schoolwork and got a fever n all so i wasn’t quite active.] Major changes i did : 1. For setup screen ( yea i’m still and still lost there): Last time, we had choosing a language in first step then answer some questions for the app to know u better but but it was only in english right like u choose the lanuage and the questions come in jus english and the Bottom Navigation Bar items where only converted into ur language buttttt i thought that why not covert the whole options and questions in ur language soooooo now tutorio converts IN 27 LANGUAGES the sec u choose the language ( i udpated 27 json files) and even greets u and motivates u in ur own language in the homescreen 2. Homescreen ( yea smthg new): yea i finally did smthg for the homescreen Now we 4 major sections home,leaderboard,test,profile and the homescreen greets u in ur language and has the top score board so when i have real users the app will show who got the highest test score in that 24 HOURS and then we have 4 modules and now ta i have made only outer screen ( i have add all course inside each modules and chapterwise test and have gemini api give u answers acc to ur ed system and learning style) So, thats it i have 27 LANGUAGE converting and a decent homescreen and yea Errors 😭:Cloudfirestore : Yea, I was running my app then suddenly when i choose a language it hit a error and boom everything was red and yellow warnings. I was so afraid and was thinking maybe i forgot to add a language in maindart or hsd and i was so freaked out and then i started to redo i activities then i realized i hadnt done billing in firestore when a created a database (i’m 15 , so no credit cards) yea i searched up for options then learned about storing locally and used sharedpreferences in flutter to keep everything running locally. Thanks for catching up and i’ll try to be more regular...
|
1792921849.0049782
|
1793785849.0049782
|
|
54929
|
Wisp by @TCG | Stardance
|
TCG
|
0
|
97.43
|
0
|
[]
|
[{"post_id": 81791, "ts": "202 [{"post_id": 81791, "ts": "2026-10-22T15:12:11Z", "hours": 5.3231, "text": "first static fire test!!!"}, {"post_id": 80182, "ts": "2026-10-16T16:07:41Z", "hours": 13.0125, "text": "before flying my rocket i wanted to validate that the firmware is working, for that i created simulated versions of sensor and actuator classes and injected them into the dependency chain and everything is working! i cant wait to fly this thing, here is a video of a simulation"}, {"post_id": 77340, "ts": "2026-10-06T16:50:10Z", "hours": 13.5108, "text": "im almost ready to fly! the only things missing are the log system on the rocket and tuning the pid, i will probably do a static fire this week!!"}, {"post_id": 76055, "ts": "2026-10-02T06:46:15Z", "hours": 15.7911, "text": "devlog #5, almost ready to static fire my tcv modle rocket! i have been working on the rocket monitor app and validated all systems, the only thing missing at this point is implementing the final radio commands for a launch, optionaly a pretty ui and transfering the log file over radio after the landing."}, {"post_id": 70659, "ts": "2026-09-19T15:21:06Z", "hours": 3.0878, "text": "i just went on a 3h UI sidequest adding completely unnecessary spotlights and a colorful polar coordinate system to the completely unnecessary 3D scene in my TVC model rocket control app, cuz i dont want to keep working on the rockets firmware"}, {"post_id": 70512, "ts": "2026-09-19T09:36:28Z", "hours": 12.5019, "text": "i made a lot of progress on the firmwear for the tvc rocket and the desktop controll center app, it now displays live imu and barometer data, the gimbal is now also working."}, {"post_id": 68690, "ts": "2026-09-15T15:27:34Z", "hours": 11.5517, "text": "devlog #4: i am working on the desktop app that will act as an controll center for the flights and testing, so far i have a few components down, i developed the protocol for the comunication over radio and to the radio device over usb, that was a lot of work because i never did anything with netwoking before but its all working now, this is a screenshot of the app so far and a graphic of the protocol i came up with (graphic made with claude)"}, {"post_id": 65858, "ts": "2026-09-11T08:59:25Z", "hours": 0.4314, "text": "OMG i just realised i routed Serial TX to TX and RX to RX on my pcb. I already orderd it so its to late now, i swear i checked this desing 5 times how did i miss this??? luckly there wont be too mutch data going though this so i can use SoftwearSerail for this but still i guess u never get rx and tx right the first time…"}, {"post_id": 65850, "ts": "2026-09-11T08:22:57Z", "hours": 3.6503, "text": "I’m somewhat done with the hardware. The flight computer arrived, and the selfdesigned PCB worked on the first try! I haven’t tested everything yet, but the buck-boost converter, battery protection, LDO, MCU, radio, and buzzer all work. I also almost finished 3D printing the rocket, only the body tube is still missing. I’m shooting for a dry mass of 170 g, and I’m well within that budget, so everything is going well so far. Next, I will be working on the communication protocol between the rocket and the ground station, and then write the firmware for the rocket."}, {"post_id": 58140, "ts": "2026-08-30T14:28:37Z", "hours": 18.5669, "text": "Hi, im building a model rocket that can actively control its accent by changing the direction its rocket motor points (thrust vector control or TVC). this is my first devlog i have been working on this for a month now but only recently heard about stardance so i already have made a lot of progress. Im done with modeling the rocket in onshape i also already desingd its flight conputer (alacer-1) and a usb to radio apter i call rocket-link in kicad. the flight computer is in production and the rocket link already arrived, so at the moment im writing the firmwear for it, developing a desktop app to act as a command center."}]...
|
Title: Wisp by @TCG | Stardance
Devlogs:
Hi, im b Title: Wisp by @TCG | Stardance
Devlogs:
Hi, im building a model rocket that can actively control its accent by changing the direction its rocket motor points (thrust vector control or TVC). this is my first devlog i have been working on this for a month now but only recently heard about stardance so i already have made a lot of progress. Im done with modeling the rocket in onshape i also already desingd its flight conputer (alacer-1) and a usb to radio apter i call rocket-link in kicad. the flight computer is in production and the rocket link already arrived, so at the moment im writing the firmwear for it, developing a desktop app to act as a command center.
I’m somewhat done with the hardware. The flight computer arrived, and the selfdesigned PCB worked on the first try! I haven’t tested everything yet, but the buck-boost converter, battery protection, LDO, MCU, radio, and buzzer all work. I also almost finished 3D printing the rocket, only the body tube is still missing. I’m shooting for a dry mass of 170 g, and I’m well within that budget, so everything is going well so far. Next, I will be working on the communication protocol between the rocket and the ground station, and then write the firmware for the rocket.
OMG i just realised i routed Serial TX to TX and RX to RX on my pcb. I already orderd it so its to late now, i swear i checked this desing 5 times how did i miss this??? luckly there wont be too mutch data going though this so i can use SoftwearSerail for this but still i guess u never get rx and tx right the first time…
devlog #4: i am working on the desktop app that will act as an controll center for the flights and testing, so far i have a few components down, i developed the protocol for the comunication over radio and to the radio device over usb, that was a lot of work because i never did anything with netwoking before but its all working now, this is a screenshot of the app so far and a graphic of the protocol i came up with (graphic made with claude)
i made a lot of progress on the firmwear for the tvc rocket and the desktop controll center app, it now displays live imu and barometer data, the gimbal is now also working.
i just went on a 3h UI sidequest adding completely unnecessary spotlights and a colorful polar coordinate system to the completely unnecessary 3D scene in my TVC model rocket control app, cuz i dont want to keep working on the rockets firmware
devlog #5, almost ready to static fire my tcv modle rocket! i have been working on the rocket monitor app and validated all systems, the only thing missing at this point is implementing the final radio commands for a launch, optionaly a pretty ui and transfering the log file over radio after the landing.
im almost ready to fly! the only things missing are the log system on the rocket and tuning the pid, i will probably do a static fire this week!!
before flying my rocket i wanted to validate that the firmware is working, for that i created simulated versions of sensor and actuator classes and injected them into the dependency chain and everything is working! i cant wait to fly this thing, here is a video of a simulation
first static fire test!!!...
|
1792810288.925927
|
1793415088.925927
|
|
34601
|
Tempo by @evanssidhu | Stardance
|
evanssidhu
|
2
|
97.0
|
1805
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T05:07:17Z", "hours": 4.0, "multiplier": 11.52, "payout": 50, "blessing": "neutral", "text": "This is the second ship of the project. This is a pretty small ship aimed at addressing some feedback posted during my last ship. Originally I planned to do a complete UI overhaul, but I decided to just focus on minor improvements now since I have to balance projects with school and don’t know if I am going to have time to work on projects as much. I also want to take a little break from projects to focus on my mental health as well since I have been dedicating multiple hours almost every day purely on making projects. Anyways, enough about that and back to the project. If you want to see the changes from the previous ship, I have them outlined in the devlog below. If you want to see the main features added in the first ship, I have it posted as well shortly below to read. Thank you and I hope you like using my project, if you have any more feedback please outline it in your vote message as I love hearing how I can make my projects better. If you do not want to scroll down to the previous ship message or the readme, here is it posted below. Previous Ship Message Tempo is finally complete. It took way too many hours to finish, mostly through self inflicted pain of using hooks instead of asynchronous functions for the engine. I know that this might not be the greatest project for how long it took, but I am proud to say that it’s finally been shipped even after the many times I wanted to quit. I made this project because I play a little bit of chess and after getting limited to only 1 game review per day I thought it would be a good idea to make my own game review (yes I know other sites exist but wheres the fun in that). Anyways enough about that, here are the project features (definetly not copied from the readme) Features Game Review: Check how well you played in your previous games by simply entering your chess.com username or by manually loading a pgn file. Move Feedback: Instant updates on how well the engine thinks your move is. Move Classifications: How well the engine evaluates your moves. Classifications such as Miss, Great, or Brilliant are also included. Engine Lines: What the engine thinks is the best line to play in a position. Accuracies: How accurate you played relative to the best moves Graph: A visual and interactive graph on how much your expected win percentage changed throughout a game Classification Report: A total summary of how many of each type of move you played History Tree: View the total game history and easily branch off the main path. Play: Play against a friend in person, or play against the engine. Custom positions can be used as well. Custom Positions: Set up a custom position to load later. Settings: Change the app or board theme. If you are still reading this, thank you and I hope you enjoy using my site.", "repo": "https://github.com/es1228/Tempo", "demo": "https://es1228.github.io/Tempo/"}, {"ship_num": 2, "ts": "2026-08-16T22:48:34Z", "hours": 93.0, "multiplier": 18.77, "payout": 1755, "blessing": "neutral", "text": "Ship Message Tempo is finally complete. It took way too many hours to finish, mostly through self inflicted pain of using hooks instead of asynchronous functions for the engine. I know that this might not be the greatest project for how long it took, but I am proud to say that it’s finally been shipped even after the many times I wanted to quit. I made this project because I play a little bit of chess and after getting limited to only 1 game review per day I thought it would be a good idea to make my own game review (yes I know other sites exist but wheres the fun in that). Anyways enough about that, here are the project features (definetly not copied from the readme) Features Game Review: Check how well you played in your previous games by simply entering your chess.com username or by manually loading a pgn file. Move Feedback: Instant updates on how well the engine thinks your move is. Move Classifications: How well the engine evaluates your moves. Classifications such as Miss, Great, or Brilliant are also included. Engine Lines: What the engine thinks is the best line to play in a position. Accuracies: How accurate you played relative to the best moves Graph: A visual and interactive graph on how much your expected win percentage changed throughout a game Classification Report: A total summary of how many of each type of move you played History Tree: View the total game history and easily branch off the main path. Play: Play against a friend in person, or play against the engine. Custom positions can be used as well. Custom Positions: Set up a custom position to load later. Settings: Change the app or board theme. If you are still reading this, thank you and I hope you enjoy using my site.", "repo": "https://github.com/es1228/Tempo", "demo": "https://es1228.github.io/Tempo/"}]...
|
[{"post_id": 63372, "ts": "202 [{"post_id": 63372, "ts": "2026-09-07T04:54:05Z", "hours": 0.6231, "text": "Devlog 24 Small devlog, I was about to do another ship after addressing the feedback from last time, but I noticed a small bug where brilliant moves did not show sometimes. It turns out the issue was much simpler than I was testing for and it was due to a small multiplication sign error when converting the mate evaluation to centipawns to check if a move was winning."}, {"post_id": 63350, "ts": "2026-09-07T03:58:57Z", "hours": 3.7075, "text": "Devlog 23 Hello again everybody! I know its been a long time since I last worked on this project, but I read the feedback on this project and addressed your suggestions. Most of the feedback was on ui/ux improvements, so as a result I removed all mentions of infinity/nan on the site, as it looks rather unpolished and unprofessional. I also changed the modal dialogs from the built in alert function to a less intrusive custom toast notification. Lastly, a couple people said the engine took slightly long to make moves, so I slightly lowered the engine depth for games and also removed another delay I originally added to make the engine feel more human like in its thinking time. In terms of the game review engine I decided to keep it the same as it works pretty quickly due to a worker pool being used, but I did change the dialog slightly to make it feel like something is happening in the background, which suprisingly actually makes it feel faster. Anyways, to everyone that tried this project and gave feedback, thank you as it was much appreciated."}, {"post_id": 48501, "ts": "2026-08-16T21:30:43Z", "hours": 1.5022, "text": "Devlog 22 The site is now live. I actually had a lot of issues in deploying this site for some reason (mainly due to the large stockfish binaries stored in git lfs and the coi serviceworker) and my deployments just kept failing. I eventually got it straightened out now and I am ready to ship the project."}, {"post_id": 47758, "ts": "2026-08-15T21:57:35Z", "hours": 2.4678, "text": "Devlog 21 The history view has finally been properly migrated to a tree structure. Now since that is finally complete, I know it has been long overdue but it is finally time to ship this project."}, {"post_id": 47293, "ts": "2026-08-15T04:37:46Z", "hours": 6.0658, "text": "Devlog 20 Another devlog here focusing on bug fixes, and I am happy to say that almost everything is pretty much complete. I’ve fixed pretty much every out of sync issue, and even got game reviews to load pretty much instantly. It literally took only around 5 seconds to load a 65 move game, so that is finally optimized. I think the issue was some web workers were not terminating properly and taking up too much memory. Anyways I hope to finally have this project out very soon, and the only thing I might to is try to get the history tree working. Today I actually did kind of get it to work but it caused massive performance degradations for some reason and was causing some conflicts with other components as well."}, {"post_id": 47078, "ts": "2026-08-14T18:24:08Z", "hours": 4.785, "text": "Devlog 19 More progress has been made adding features and fixing bugs. I’ll highlight the changes below. Features Game Chart The game chart has been updated to include custom dots and lines showing the move classifications and key points during the game (brilliant moves, great moves, mistake, blunder, and miss). You can also click on the chart to go to that move. History View The history view has now been updated to show the classification icons next to the move, which should make it easier to find moves you are looking for Fixes/Optimizations Memoization Data in the game chart has now been memoized. This prevents the chart from crashing the page due to trying to process data many times per second. Stockfish evaluations Game review evaluations now use an active worker pool to run multiple evaluations at once rather than just one at a time. Positions are also cached now so all evaluations share 1 chess instance. In practice, this has reduced the game review time for a 20 move game from over 1 minute to around 7 seconds, which is around a 90% decrease."}, {"post_id": 46601, "ts": "2026-08-13T23:14:42Z", "hours": 2.3281, "text": "Devlog 18 A few things in this devlog, I separated the game review panel into 2 sections containing the review report and engine analysis. I’ve also refined the classifications for great and brilliant. Brilliant Move Changes The sacrifice can now be anywhere on the board, not just for the piece that moved Trading a lower value piece for a higher value piece (ex: taking a knight but losing a pawn) no longer counts as brilliant Illegal moves (pins, checks, etc.,) no longer contribute to the attacking piece values Great Move Changes Taking a hanging piece or trading lower value pieces for higher value pieces (ex: capturing a hanging queen or recapturing during a trade) no longer count as great moves."}, {"post_id": 46134, "ts": "2026-08-13T04:37:45Z", "hours": 1.8517, "text": "Devlog 17 After a long time, I’ve finally added brilliant moves. This was done by comparing a squares attackers and defenders to determine if the piece is hanging. If a move results in that piece being hanging/sacrificed, and is the top engine move, then the classification will return brilliant. I’ve attached an example below in a game where GothamChess does what he does best and sacrifices both his rooks."}, {"post_id": 46084, "ts": "2026-08-13T01:13:20Z", "hours": 3.2308, "text": "Devlog 16 I’ve added the last 2 features related to game review, accuracies and the eval chart. The last thing I plan to to is add some polish, brilliant moves, and maybe try working on the history/pgn tree again."}, {"post_id": 45932, "ts": "2026-08-12T18:35:37Z", "hours": 2.4761, "text": "Devlog 15 I’ve added a few more features related to game review in this devlog. First, I added a section to view the top 2 engine lines on each move. I’ve also added a table to view classifications for the entire game."}, {"post_id": 45416, "ts": "2026-08-11T20:58:03Z", "hours": 0.9417, "text": "Devlog 14 I’m going to post more frequently as this project gets wrapped up, and I’ve just finished caching the game review data so feedback is instant if you load in game to review. I also decided to add colors to the start and end squares based on classification because it looks nice. I’ve attached a video below, I don’t know why my screen recorder records very laggy but I promise it’s not actually that laggy."}, {"post_id": 45004, "ts": "2026-08-11T04:20:50Z", "hours": 4.3753, "text": "Devlog 13 I’ve been working on the game review stats, and i’ve implemented a function to classify an entire game and tally up the classifications (which was actually harder than it looked, since i needed to rewrite my hooks since hooks cannot be called within functions). It now works pretty decently, but I do want to optimize performance a bit since it takes a while. Funnily enough there was an issue where if the worker resolved too early it would not terminate and create a memory leak and eat your entire system memory, but thats fixed now."}, {"post_id": 44308, "ts": "2026-08-09T23:45:35Z", "hours": 7.9586, "text": "Devlog 12 I really don’t like going this long without posting a devlog, but debugging move classifications was really painful. I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation. I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work. I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain. Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex.# Devlog 12 I really don’t like going this long without posting a devlog, but debugging move classifications was really painful. I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation. I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work. I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain. Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex."}, {"post_id": 41619, "ts": "2026-08-05T22:47:45Z", "hours": 2.9967, "text": "Devlog 11 I am finally back to this project, and this time did not wait 8 hours to post a devlog. Anyways, I added two major features today, custom position imports (which I forgot to do last time) and engine play. Features Custom Position Imports You can now import a position into the custom position editor, which is great for things like loading puzzles and endgames to practice against the engine. You can also export positions by pressing the copy button to copy the position fen to the clipboard. Play Against Engine You can now play games against stockfish, and choose a difficulty level from 0-20. As mentioned above I believe this is a quite useful feature for things like just playing by yourself or practicing different endgames against the computer. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View Play In Person Custom Position Setup Play Against Engine Full Game Review/Engine Analysis (In Progress) Brilliant Moves"}, {"post_id": 37328, "ts": "2026-07-29T23:27:39Z", "hours": 8.7039, "text": "Devlog 10 I finished work on in-person gameplay and custom position setups, all that is left now is to finish adding engine play, polish game review, and add brilliant moves. Promotions You can now choose the piece you would like to promote to (no longer auto queen). In Person Play You can now create a game to be played in person between 2 people. Time controls are also availible. Custom Positions You can now load custom positions via drag and drop, which is useful for practicing endgames or creating puzzles. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View Play In Person Custom Position Setup [] Full Game Review/Engine Analysis (In Progress) Play Against Engine (In Progress) Brilliant Moves"}, {"post_id": 36679, "ts": "2026-07-28T21:54:34Z", "hours": 8.5064, "text": "Devlog 9 I tried to convert the history from a linear array into a tree, and it did not go well. I spent literal hours trying to get it to work and look at tutorials, but it just did not want to work. So for now i’ve decided to stop working on that feature, and just focus on the last few remaining tasks. I do have to fix a couple of things since a lot of features are currently in progress, but I will post another devlog later showing the updated features."}, {"post_id": 34189, "ts": "2026-07-24T18:26:16Z", "hours": 7.4164, "text": "Devlog 8 Sorry again for the long devlog, some things took a bit longer than I expected. Anyways, icons/glyphs have been added in this devlog. I’ve also fixed some issues with move backtracking. Additional classifications such as miss and great have been added, which took a while since I had to do a lot of refactors to store all the data in cache, and I also didn’t realize I sometimes was tracking the evaluations for the next moves, not the ones just played, which took a while New classifications Miss : Miss is when the previous player makes a bad move, but the next player fails to capitalize on it causing the evaluation to drop back to near where it was before. Great : Great moves are the only moves in the position that work, provided that the outcome is drawn or winning and you are not already winning had you not played the move. It compares 2 lines of stockfish to evaluate the evaluation difference and check for the conditions outlined above. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View (In Progress) Full Game Review/Engine Analysis (In Progress) Play In Person Play Against Engine Custom Position Setup Brilliant Moves"}, {"post_id": 33467, "ts": "2026-07-23T13:22:55Z", "hours": 2.5939, "text": "Devlog 7 Lots of QOL features and fixes added today, i’ve added a basic view of move history, and added a settings page where you can change the theme of the website or board. Next, I do want to work on features that do not involve the game review, such as pass and play or engine play. Move History You can now properly go through a game’s moves and view all played moves in the side pane. Themes Website theming has been added, alongside being able to choose the colors you would like the board to be. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles History View (In Progress) Full Game Review/Engine Analysis (In Progress) Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)"}, {"post_id": 32763, "ts": "2026-07-22T03:57:08Z", "hours": 3.5231, "text": "Devlog 6 Second devlog today, this is more of an extension of the previous devlog since a lot of features were not fully polished yet. Since then move playback has been added and I also added a game review container. Most of the logic has now been implemented, all thats left now is a little polish and styling. The only logic thats left is trying to find a way to add proper move history and advanced classifications. I also attached a demo video this time since I forgot to last devlog. Move Playback It is now possible to use arrows to traverse forwards and backwards if a PGN file is imported. Game Review Container I added a little side container which will be used to show the stats of the game review. Currently it only shows the opening and move feedback, but it will be expanded to show accuracies and a full breakdown of the analysis and position similar to chess.com. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls History View Board Themes/Styles Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant) Changelog 0e4db3c e2552b0"}, {"post_id": 32610, "ts": "2026-07-21T21:52:00Z", "hours": 8.4406, "text": "Devlog 5 Sorry for the long devlog, some things took longer than expected. First I decided to waste time trying to improve the UI until I remembered I suck at design and just decided to revert to the original design. Then I spent forever wondering why my input textbox would not work properly just for me to change e.target.value to e.currentTarget.value. Although I guess where would the fun be if there was no struggle. Anyways, here are the features I added. Board Controls It is now possible to flip the board and go forwards and backwards through moves. Importing from other sources This one took a bit of time, but now you can import games from Chess.com, or provide your own PGN/FEN. Later on I’ll probably also add Lichess as an import source as well. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, Lichess, etc.,) (In Progress) Playback/History Controls (In Progress) Board Themes/Styles Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)"}, {"post_id": 31026, "ts": "2026-07-19T02:37:20Z", "hours": 3.3967, "text": "Devlog 4 Site Styling Site styling has been added in this commit, and it also comes with light/dark mode. The evaluation bar has also been added, and is responsive based on the win probability formula. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Themes/Styles Play In Person Play Against Engine Playback/History Controls Importing from other sources (FEN, PGN, Chess.com, Lichess, etc.,) Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)"}, {"post_id": 30437, "ts": "2026-07-17T23:52:15Z", "hours": 4.6394, "text": "Devlog 3 Move Classifications Move classifications have finally been added. I thought it wouldn’t take this long but instead I spent hours trying to deal with react asynchronous state and trying to coordinate different hooks to play along nicely. Thankfully it works properly now (hopefully). The classifications added are best, excellent, good, inaccuracy, mistake, blunder, and theory. Opening names have also been added as well. Next Steps Next, I’ll work on making the site actually look pretty and have functionality. Importing games should also come next after that. Towards the end i’ll add other classifications as well such as miss, great, and brilliant, however, I expect them to be more difficult as they have slightly stricter classifications."}, {"post_id": 29258, "ts": "2026-07-16T01:54:05Z", "hours": 3.6022, "text": "Devlog 2 Playable Chess! There is now a playable UI to play Chess games. This was done using a mix of chess.js for the logic and react-chessboard for the UI. Most of the logic was handled by the board, however click/drag to move took some time to add. There is also positional evaluations and engine feedback now. Next Steps Next, I plan on creating the actual site design and controls. I also want to add a way to import games from sites like chess.com, and have the ability to load a full game rather than just a position. Move classification is also something that should be implemented soon. Demo Video"}, {"post_id": 28068, "ts": "2026-07-14T02:54:31Z", "hours": 1.6744, "text": "Devlog 1 I started work on Tempo, a chess analysis site to review your games. Chess engines such as Stockfish are easily self-hostable anyways, so there is no reason for sites like chess.com to limit game analysis to 1 per day. What’s New Added move analysis using Stockfish, which is fully selfhosted. Figuring out web workers and UCI was pretty time consuming, but eventually I got the hang of it and figured it out. Next Steps Next, I plan to work on creating the chessboard and site UI. Later I’ll add move classifications such as “Blunder”, “Mistake”, “Excellent”, etc. Maybe i’ll add “Brilliant” moves, but there seems to be no clear definition of one other than “a good sacrifice”."}]...
|
Title: Tempo by @evanssidhu | Stardance
Devlogs:
Title: Tempo by @evanssidhu | Stardance
Devlogs:
Devlog 1 I started work on Tempo, a chess analysis site to review your games. Chess engines such as Stockfish are easily self-hostable anyways, so there is no reason for sites like chess.com to limit game analysis to 1 per day. What’s New Added move analysis using Stockfish, which is fully selfhosted. Figuring out web workers and UCI was pretty time consuming, but eventually I got the hang of it and figured it out. Next Steps Next, I plan to work on creating the chessboard and site UI. Later I’ll add move classifications such as “Blunder”, “Mistake”, “Excellent”, etc. Maybe i’ll add “Brilliant” moves, but there seems to be no clear definition of one other than “a good sacrifice”.
Devlog 2 Playable Chess! There is now a playable UI to play Chess games. This was done using a mix of chess.js for the logic and react-chessboard for the UI. Most of the logic was handled by the board, however click/drag to move took some time to add. There is also positional evaluations and engine feedback now. Next Steps Next, I plan on creating the actual site design and controls. I also want to add a way to import games from sites like chess.com, and have the ability to load a full game rather than just a position. Move classification is also something that should be implemented soon. Demo Video
Devlog 3 Move Classifications Move classifications have finally been added. I thought it wouldn’t take this long but instead I spent hours trying to deal with react asynchronous state and trying to coordinate different hooks to play along nicely. Thankfully it works properly now (hopefully). The classifications added are best, excellent, good, inaccuracy, mistake, blunder, and theory. Opening names have also been added as well. Next Steps Next, I’ll work on making the site actually look pretty and have functionality. Importing games should also come next after that. Towards the end i’ll add other classifications as well such as miss, great, and brilliant, however, I expect them to be more difficult as they have slightly stricter classifications.
Devlog 4 Site Styling Site styling has been added in this commit, and it also comes with light/dark mode. The evaluation bar has also been added, and is responsive based on the win probability formula. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Themes/Styles Play In Person Play Against Engine Playback/History Controls Importing from other sources (FEN, PGN, Chess.com, Lichess, etc.,) Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)
Devlog 5 Sorry for the long devlog, some things took longer than expected. First I decided to waste time trying to improve the UI until I remembered I suck at design and just decided to revert to the original design. Then I spent forever wondering why my input textbox would not work properly just for me to change e.target.value to e.currentTarget.value. Although I guess where would the fun be if there was no struggle. Anyways, here are the features I added. Board Controls It is now possible to flip the board and go forwards and backwards through moves. Importing from other sources This one took a bit of time, but now you can import games from Chess.com, or provide your own PGN/FEN. Later on I’ll probably also add Lichess as an import source as well. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, Lichess, etc.,) (In Progress) Playback/History Controls (In Progress) Board Themes/Styles Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)
Devlog 6 Second devlog today, this is more of an extension of the previous devlog since a lot of features were not fully polished yet. Since then move playback has been added and I also added a game review container. Most of the logic has now been implemented, all thats left now is a little polish and styling. The only logic thats left is trying to find a way to add proper move history and advanced classifications. I also attached a demo video this time since I forgot to last devlog. Move Playback It is now possible to use arrows to traverse forwards and backwards if a PGN file is imported. Game Review Container I added a little side container which will be used to show the stats of the game review. Currently it only shows the opening and move feedback, but it will be expanded to show accuracies and a full breakdown of the analysis and position similar to chess.com. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls History View Board Themes/Styles Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant) Changelog 0e4db3c e2552b0
Devlog 7 Lots of QOL features and fixes added today, i’ve added a basic view of move history, and added a settings page where you can change the theme of the website or board. Next, I do want to work on features that do not involve the game review, such as pass and play or engine play. Move History You can now properly go through a game’s moves and view all played moves in the side pane. Themes Website theming has been added, alongside being able to choose the colors you would like the board to be. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles History View (In Progress) Full Game Review/Engine Analysis (In Progress) Play In Person Play Against Engine Custom Position Setup Advanced Classifications (Miss, Great, Brilliant)
Devlog 8 Sorry again for the long devlog, some things took a bit longer than I expected. Anyways, icons/glyphs have been added in this devlog. I’ve also fixed some issues with move backtracking. Additional classifications such as miss and great have been added, which took a while since I had to do a lot of refactors to store all the data in cache, and I also didn’t realize I sometimes was tracking the evaluations for the next moves, not the ones just played, which took a while New classifications Miss : Miss is when the previous player makes a bad move, but the next player fails to capitalize on it causing the evaluation to drop back to near where it was before. Great : Great moves are the only moves in the position that work, provided that the outcome is drawn or winning and you are not already winning had you not played the move. It compares 2 lines of stockfish to evaluate the evaluation difference and check for the conditions outlined above. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View (In Progress) Full Game Review/Engine Analysis (In Progress) Play In Person Play Against Engine Custom Position Setup Brilliant Moves
Devlog 9 I tried to convert the history from a linear array into a tree, and it did not go well. I spent literal hours trying to get it to work and look at tutorials, but it just did not want to work. So for now i’ve decided to stop working on that feature, and just focus on the last few remaining tasks. I do have to fix a couple of things since a lot of features are currently in progress, but I will post another devlog later showing the updated features.
Devlog 10 I finished work on in-person gameplay and custom position setups, all that is left now is to finish adding engine play, polish game review, and add brilliant moves. Promotions You can now choose the piece you would like to promote to (no longer auto queen). In Person Play You can now create a game to be played in person between 2 people. Time controls are also availible. Custom Positions You can now load custom positions via drag and drop, which is useful for practicing endgames or creating puzzles. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View Play In Person Custom Position Setup [] Full Game Review/Engine Analysis (In Progress) Play Against Engine (In Progress) Brilliant Moves
Devlog 11 I am finally back to this project, and this time did not wait 8 hours to post a devlog. Anyways, I added two major features today, custom position imports (which I forgot to do last time) and engine play. Features Custom Position Imports You can now import a position into the custom position editor, which is great for things like loading puzzles and endgames to practice against the engine. You can also export positions by pressing the copy button to copy the position fen to the clipboard. Play Against Engine You can now play games against stockfish, and choose a difficulty level from 0-20. As mentioned above I believe this is a quite useful feature for things like just playing by yourself or practicing different endgames against the computer. Roadmap Stockfish Web Worker Chessboard/Gameplay Basic Classifications Opening Names Evaluation Bar Site Styling Board Controls Importing from other sources (FEN, PGN, Chess.com, etc.,) Playback Controls Board Themes/Styles Miss and Great moves History View Play In Person Custom Position Setup Play Against Engine Full Game Review/Engine Analysis (In Progress) Brilliant Moves
Devlog 12 I really don’t like going this long without posting a devlog, but debugging move classifications was really painful. I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation. I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work. I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain. Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex.# Devlog 12 I really don’t like going this long without posting a devlog, but debugging move classifications was really painful. I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation. I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work. I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain. Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex.
Devlog 13 I’ve been working on the game review stats, and i’ve implemented a function to classify an entire game and tally up the classifications (which was actually harder than it looked, since i needed to rewrite my hooks since hooks cannot be called within functions). It now works pretty decently, but I do want to optimize performance a bit since it takes a while. Funnily enough there was an issue where if the worker resolved too early it would not terminate and create a memory leak and eat your entire system memory, but thats fixed now.
Devlog 14 I’m going to post more frequently as this project gets wrapped up, and I’ve just finished caching the game review data so feedback is instant if you load in game to review. I also decided to add colors to the start and end squares based on classification because it looks nice. I’ve attached a video below, I don’t know why my screen recorder records very laggy but I promise it’s not actually that laggy.
Devlog 15 I’ve added a few more features related to game review in this devlog. First, I added a section to view the top 2 engine lines on each move. I’ve also added a table to view classifications for the entire game.
Devlog 16 I’ve added the last 2 features related to game review, accuracies and the eval chart. The last thing I plan to to is add some polish, brilliant moves, and maybe try working on the history/pgn tree again.
Devlog 17 After a long time, I’ve finally added brilliant moves. This was done by comparing a squares attackers and defenders to determine if the piece is hanging. If a move results in that piece being hanging/sacrificed, and is the top engine move, then the classification will return brilliant. I’ve attached an example below in a game where GothamChess does what he does best and sacrifices both his rooks.
Devlog 18 A few things in this devlog, I separated the game review panel into 2 sections containing the review report and engine analysis. I’ve also refined the classifications for great and brilliant. Brilliant Move Changes The sacrifice can now be anywhere on the board, not just for the piece that moved Trading a lower value piece for a higher value piece (ex: taking a knight but losing a pawn) no longer counts as brilliant Illegal moves (pins, checks, etc.,) no longer contribute to the attacking piece values Great Move Changes Taking a hanging piece or trading lower value pieces for higher value pieces (ex: capturing a hanging queen or recapturing during a trade) no longer count as great moves.
Devlog 19 More progress has been made adding features and fixing bugs. I’ll highlight the changes below. Features Game Chart The game chart has been updated to include custom dots and lines showing the move classifications and key points during the game (brilliant moves, great moves, mistake, blunder, and miss). You can also click on the chart to go to that move. History View The history view has now been updated to show the classification icons next to the move, which should make it easier to find moves you are looking for Fixes/Optimizations Memoization Data in the game chart has now been memoized. This prevents the chart from crashing the page due to trying to process data many times per second. Stockfish evaluations Game review evaluations now use an active worker pool to run multiple evaluations at once rather than just one at a time. Positions are also cached now so all evaluations share 1 chess instance. In practice, this has reduced the game review time for a 20 move game from over 1 minute to around 7 seconds, which is around a 90% decrease.
Devlog 20 Another devlog here focusing on bug fixes, and I am happy to say that almost everything is pretty much complete. I’ve fixed pretty much every out of sync issue, and even got game reviews to load pretty much instantly. It literally took only around 5 seconds to load a 65 move game, so that is finally optimized. I think the issue was some web workers were not terminating properly and taking up too much memory. Anyways I hope to finally have this project out very soon, and the only thing I might to is try to get the history tree working. Today I actually did kind of get it to work but it caused massive performance degradations for some reason and was causing some conflicts with other components as well.
Devlog 21 The history view has finally been properly migrated to a tree structure. Now since that is finally complete, I know it has been long overdue but it is finally time to ship this project.
Devlog 22 The site is now live. I actually had a lot of issues in deploying this site for some reason (mainly due to the large stockfish binaries stored in git lfs and the coi serviceworker) and my deployments just kept failing. I eventually got it straightened out now and I am ready to ship the project.
Devlog 23 Hello again everybody! I know its been a long time since I last worked on this project, but I read the feedback on this project and addressed your suggestions. Most of the feedback was on ui/ux improvements, so as a result I removed all mentions of infinity/nan on the site, as it looks rather unpolished and unprofessional. I also changed the modal dialogs from the built in alert function to a less intrusive custom toast notification. Lastly, a couple people said the engine took slightly long to make moves, so I slightly lowered the engine depth for games and also removed another delay I originally added to make the engine feel more human like in its thinking time. In terms of the game review engine I decided to keep it the same as it works pretty quickly due to a worker pool being used, but I did change the dialog slightly to make it feel like something is happening in the background, which suprisingly actually makes it feel faster. Anyways, to everyone that tried this project and gave feedback, thank you as it was much appreciated.
Devlog 24 Small devlog, I was about to do another ship after addressing the feedback from last time, but I noticed a small bug where brilliant moves did not show sometimes. It turns out the issue was much simpler than I was testing for and it was due to a small multiplication sign error when converting the mate evaluation to centipawns to check if a move was winning.
Ships:
Ship Message Tempo is finally complete. It took way too many hours to finish, mostly through self inflicted pain of using hooks instead of asynchronous functions for the engine. I know that this might not be the greatest project for how long it took, but I am proud to say that it’s finally been shipped even after the many times I wanted to quit. I made this project because I play a little bit of chess and after getting limited to only 1 game review per day I thought it would be a good idea to make my own game review (yes I know other sites exist but wheres the fun in that). Anyways enough about that, here are the project features (definetly not copied from the readme) Features Game Review: Check how well you played in your previous games by simply entering your chess.com username or by manually loading a pgn file. Move Feedback: Instant updates on how well the engine thinks your move is. Move Classifications: How well the engine evaluates your moves. Classifications such as Miss, Great, or Brilliant are also included. Engine Lines: What the engine thinks is the best line to play in a position. Accuracies: How accurate you played relative to the best moves Graph: A visual and interactive graph on how much your expected win percentage changed throughout a game Classification Report: A total summary of how many of each type of move you played History Tree: View the total game history and easily branch off the main path. Play: Play against a friend in person, or play against the engine. Custom positions can be used as well. Custom Positions: Set up a custom position to load later. Settings: Change the app or board theme. If you are still reading this, thank you and I hope you enjoy using my site.
This is the second ship of the project. This is a pretty small ship aimed at addressing some feedback posted during my last ship. Originally I planned to do a complete UI overhaul, but I decided to just focus on minor improvements now since I have to balance projects with school and don’t know if I am going to have time to work on projects as much. I also want to take a little break from projects to focus on my mental health as well since I have been dedicating multiple hours almost every day purely on making projects. Anyways, enough about that and back to the project. If you want to see the changes from the previous ship, I have them outlined in the devlog below. If you want to see the main features added in the first ship, I have it posted as well shortly below to read. Thank you and I hope you like using my project, if you have any more feedback please outline it in your vote message as I love hearing how I can make my projects better. If you do not want to scroll down to the previous ship message or the readme, here is it posted below. Previous Ship Message Tempo is finally complete. It took way too many hours to finish, mostly through self inflicted pain of using hooks instead of asynchronous functions for the engine. I know that this might not be the greatest project for how long it took, but I am proud to say that it’s finally been shipped even after the many times I wanted to quit. I made this project because I play a little bit of chess and after getting limited to only 1 game review per day I thought it would be a good idea to make my own game review (yes I know other sites exist but wheres the fun in that). Anyways enough about that, here are the project features (definetly not copied from the readme) Features Game Review: Check how well you played in your previous games by simply entering your chess.com username or by manually loading a pgn file. Move Feedback: Instant updates on how well the engine thinks your move is. Move Classifications: How well the engine evaluates your moves. Classifications such as Miss, Great, or Brilliant are also included. Engine Lines: What the engine thinks is the best line to play in a position. Accuracies: How accurate you played relative to the best moves Graph: A visual and interactive graph on how much your expected win percentage changed throughout a game Classification Report: A total summary of how many of each type of move you played History Tree: View the total game history and easily branch off the main path. Play: Play against a friend in person, or play against the engine. Custom positions can be used as well. Custom Positions: Set up a custom position to load later. Settings: Change the app or board theme. If you are still reading this, thank you and I hope you enjoy using my site....
|
1792986947.8720236
|
1793073347.8720236
|
|
29599
|
Holy Moley by @GeorgeSun | Stardance
|
GeorgeSun
|
3
|
96.74
|
1613
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-07T23:43:28Z", "hours": 65.0, "multiplier": 19.59, "payout": 1513, "blessing": "neutral", "text": "Me and my friends made a game about a little mole that fights demons! There are 14 different levels, an inventory system, main menu, health system, map/quick travel system, shop system, and four different items. There are also two bossfights that multiple different attacks and are quite challenging. The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. There has been many changes since the last ship which I feel make the game a lot more complete such as the mole village where there are NPC moles for you to talk to. The game has side quests for you to accomplish now which give you exclusive unlocks that help you along your adventure. Click try project below to play on web or on PC!", "repo": "https://github.com/Geofoods/Holy-Moly", "demo": "https://bryanjietang-boop.itch.io/holy-moly"}, {"ship_num": 2, "ts": "2026-09-03T22:02:25Z", "hours": 2.0, "multiplier": 12.89, "payout": 24, "blessing": "neutral", "text": "Me and my friends made a game about a little mole that fights demons! There are nine different levels, inventory system, main menu, health system, and many different intricate systems such as the parry system! The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. I am also proud of the fact that this is now available on mobile and can be played on Andriod and Iphone! (although not available on the app store. You can play my project with the demo link! The Android version is downloadable, you just have to give it permissions. IOS needs an apple developer license however so it will take a while.", "repo": "https://github.com/Geofoods/Holy-Moly", "demo": "https://bryanjietang-boop.itch.io/holy-moly"}, {"ship_num": 3, "ts": "2026-07-10T14:24:37Z", "hours": 12.0, "multiplier": 12.93, "payout": 76, "blessing": "neutral", "text": "Me and my friends made a game about a little mole that fights demons! There are nine different levels, inventory system, main menu, health system, and many different intricate systems such as the parry system! The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. You can play my project with the demo link!", "repo": "https://github.com/Geofoods/Holy-Moly", "demo": "https://bryanjietang-boop.itch.io/holy-moly"}]...
|
[{"post_id": 82122, "ts": "202 [{"post_id": 82122, "ts": "2026-10-24T00:29:19Z", "hours": 9.1569, "text": "I created a level editor so that everyone can make their own levels. You can create blocks, enemies, checkpoints, chests, items, decorations, and spawnpoints! You can even change the background, music, and VFX! After you have created your level, you can upload your levels to the public server so that everyone can play your level. You can also sort levels by date, likes, downloads, and keywords!"}, {"post_id": 80043, "ts": "2026-10-16T01:49:13Z", "hours": 8.5842, "text": "I polished the map menu to be more consistent to the rest of the menus in the game. I also added more selection to the shop where now you can also sell things in the shop. There are also two new weapons which is the miner’s pickaxe and the wizard’s staff which is the first ranged weapon. I also am currently working on a multiplayer battle mode."}, {"post_id": 77696, "ts": "2026-10-07T23:19:00Z", "hours": 3.3469, "text": "I made my final bugfixes and a few optimizations for web, I think you guys will really enjoy the game!"}, {"post_id": 77189, "ts": "2026-10-06T00:18:02Z", "hours": 10.3744, "text": "This will probably be the final devlog as the game is super close to being finished! I added houses that the mole can enter and also added an extra phase to the corrupted snail boss. There are also new quests for you to partipate in and there are more points for you to quick travel from. I also added in some more music and sound effects and more polishing. You can also now save and erase game data"}, {"post_id": 75730, "ts": "2026-09-30T21:36:11Z", "hours": 9.2133, "text": "I created a new boss called the corrupted snail which will be the final boss and also reworked the corrupted heart as well. I also added some extra story and dialogue and added a new map with quick travel so that you can travel from mole village to the shopkeeper"}, {"post_id": 73767, "ts": "2026-09-25T21:55:35Z", "hours": 7.4275, "text": "I added extra polishing to the arena such as a new enemy spawning animation, and reworked the hornets which is the new enemy that dashes into you. I also added some story and dialogue."}, {"post_id": 72415, "ts": "2026-09-22T21:35:48Z", "hours": 10.3656, "text": "I changed the colours to make the visuals more aesthetic. I also added mole village where you can talk to other moles. I also revamped the tutorial so that the player learns the controls better"}, {"post_id": 70715, "ts": "2026-09-19T17:16:05Z", "hours": 8.8269, "text": "There are now new enemies such as hornets and I have been working on a lot of new levels for my open world 2d platformer called Holy Moly!"}, {"post_id": 69410, "ts": "2026-09-17T00:24:37Z", "hours": 7.6839, "text": "I want to make this an Open World 2D Platformer Game so I have it so that you can travel between levels freely without select screen. I also changed the lighting and added various QOL features"}, {"post_id": 68317, "ts": "2026-09-14T22:37:20Z", "hours": 5.8411, "text": "Made a new shop UI, cave system, and a dynamic camera. I also changed the block breaking physics so that the dirt particles have physics and also added ranged weapons and a grappling hook"}, {"post_id": 64521, "ts": "2026-09-09T00:01:03Z", "hours": 2.0364, "text": "I created a world system where are the levels are connected and also added a damage indicator when hitting enemies and how much damage you inflicted. I also tweaked the combat system so now there is an aerial attack when you attack in the air which is faster than ground attacking"}, {"post_id": 52028, "ts": "2026-08-22T02:07:00Z", "hours": 1.5547, "text": "I ported my Game onto Android and Apple phones and added mobile support!"}, {"post_id": 23539, "ts": "2026-07-06T15:49:12Z", "hours": 10.8819, "text": "Finished the game with 9 levels, end screen, win screen, and boss at the end. You can play the game right now!"}, {"post_id": 20425, "ts": "2026-07-02T00:51:13Z", "hours": 0.8114, "text": "Added a cave parallax background, the player sprite animations and the health indicator"}]...
|
Title: Holy Moley by @GeorgeSun | Stardance
Devlo Title: Holy Moley by @GeorgeSun | Stardance
Devlogs:
Added a cave parallax background, the player sprite animations and the health indicator
Finished the game with 9 levels, end screen, win screen, and boss at the end. You can play the game right now!
I ported my Game onto Android and Apple phones and added mobile support!
I created a world system where are the levels are connected and also added a damage indicator when hitting enemies and how much damage you inflicted. I also tweaked the combat system so now there is an aerial attack when you attack in the air which is faster than ground attacking
Made a new shop UI, cave system, and a dynamic camera. I also changed the block breaking physics so that the dirt particles have physics and also added ranged weapons and a grappling hook
I want to make this an Open World 2D Platformer Game so I have it so that you can travel between levels freely without select screen. I also changed the lighting and added various QOL features
There are now new enemies such as hornets and I have been working on a lot of new levels for my open world 2d platformer called Holy Moly!
I changed the colours to make the visuals more aesthetic. I also added mole village where you can talk to other moles. I also revamped the tutorial so that the player learns the controls better
I added extra polishing to the arena such as a new enemy spawning animation, and reworked the hornets which is the new enemy that dashes into you. I also added some story and dialogue.
I created a new boss called the corrupted snail which will be the final boss and also reworked the corrupted heart as well. I also added some extra story and dialogue and added a new map with quick travel so that you can travel from mole village to the shopkeeper
This will probably be the final devlog as the game is super close to being finished! I added houses that the mole can enter and also added an extra phase to the corrupted snail boss. There are also new quests for you to partipate in and there are more points for you to quick travel from. I also added in some more music and sound effects and more polishing. You can also now save and erase game data
I made my final bugfixes and a few optimizations for web, I think you guys will really enjoy the game!
I polished the map menu to be more consistent to the rest of the menus in the game. I also added more selection to the shop where now you can also sell things in the shop. There are also two new weapons which is the miner’s pickaxe and the wizard’s staff which is the first ranged weapon. I also am currently working on a multiplayer battle mode.
I created a level editor so that everyone can make their own levels. You can create blocks, enemies, checkpoints, chests, items, decorations, and spawnpoints! You can even change the background, music, and VFX! After you have created your level, you can upload your levels to the public server so that everyone can play your level. You can also sort levels by date, likes, downloads, and keywords!
Ships:
Me and my friends made a game about a little mole that fights demons! There are nine different levels, inventory system, main menu, health system, and many different intricate systems such as the parry system! The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. You can play my project with the demo link!
Me and my friends made a game about a little mole that fights demons! There are nine different levels, inventory system, main menu, health system, and many different intricate systems such as the parry system! The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. I am also proud of the fact that this is now available on mobile and can be played on Andriod and Iphone! (although not available on the app store. You can play my project with the demo link! The Android version is downloadable, you just have to give it permissions. IOS needs an apple developer license however so it will take a while.
Me and my friends made a game about a little mole that fights demons! There are 14 different levels, an inventory system, main menu, health system, map/quick travel system, shop system, and four different items. There are also two bossfights that multiple different attacks and are quite challenging. The most challenging part about this was making the enemy pathfinding as there were many bugs and glitches during the creation process. I am most proud of how polished the game is because the game feels very reactive and fun to play. There has been many changes since the last ship which I feel make the game a lot more complete such as the mole village where there are NPC moles for you to talk to. The game has side quests for you to accomplish now which give you exclusive unlocks that help you along your adventure. Click try project below to play on web or on PC!...
|
1793069394.3579435
|
1793155794.3579435
|
|
39941
|
Code Invaders by @RaspberryPi314 | Stardance
|
RaspberryPi314
|
1
|
96.48
|
108
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-28T00:14:38Z", "hours": 15.0, "multiplier": 7.35, "payout": 108, "blessing": "neutral", "text": "I created a space-invaders themed game with programming elements. The most challenging part was probably creating the start screen and debugging. I am proud of all the enemies , and the power-up cards. You should know that you can play my game in a itch.io browser, but it will probably be best to play on a laptop / monitor.", "repo": "https://github.com/etucoder/Code-Invaders", "demo": "https://rasppidev.itch.io/code-invaders"}]...
|
[{"post_id": 42374, "ts": "202 [{"post_id": 42374, "ts": "2026-08-07T01:56:36Z", "hours": 23.4486, "text": "Multiplayer now work 50% after working on the multiplayer for 10 hours and then deleting all of that! I love development!"}, {"post_id": 40734, "ts": "2026-08-04T13:28:18Z", "hours": 19.3281, "text": "MULTIPLAYER WORKS !(kind of). The ship movement and laser shots are now synced, but I still need to sync enemies and the shop."}, {"post_id": 39190, "ts": "2026-08-01T23:53:46Z", "hours": 10.6611, "text": "Transitioning from 3 cards at the end of each level into a shop with currency"}, {"post_id": 38417, "ts": "2026-07-31T19:34:06Z", "hours": 19.5222, "text": "I added a textbox so I can add a storyline to the game, and the game pauses while the story is playing!"}, {"post_id": 36739, "ts": "2026-07-29T00:09:39Z", "hours": 4.1808, "text": "I added 3 new weapons: Double, Shotgun, and Mines. Double shoots 2 bullets at once. Shotgun shoots 5 bullets in a fan that do 50% more Damage, but has a longer cooldown. Mines lays a mine that only activates when enemies are close, and does area damage with 100% more damage. It has the longest cooldown"}, {"post_id": 36426, "ts": "2026-07-28T15:24:51Z", "hours": 2.8953, "text": "The boss now spawns other smaller enemies from previous stages. It also has 3 attacks , a laser fan, a 3-shot cannon , and a beam from its eyes."}, {"post_id": 36323, "ts": "2026-07-28T11:35:28Z", "hours": 0.3569, "text": "Added particle explosions when a boss gets hit, but they are smaller to make the shooting feel more responsive. I may add flashing later."}, {"post_id": 36168, "ts": "2026-07-28T02:35:31Z", "hours": 1.09, "text": "Trying to Add a Boss - It has extremely high health, doesn’t move down, and there are no files during the boss fight . This will be wave 20, and the bpss will have 3 stages (but what?) It is based off of RecursionError"}, {"post_id": 36113, "ts": "2026-07-28T00:11:56Z", "hours": 3.1978, "text": "Code Invaders Devlog - Added Start Screen"}, {"post_id": 35997, "ts": "2026-07-27T20:01:23Z", "hours": 1.1283, "text": "I added the BrokenPipe Enemy… It shoots bullets (the little blue things almost at the bottom) down below that do damage to your ship and files. These enemies are based on real Python Errors"}, {"post_id": 35918, "ts": "2026-07-27T17:49:49Z", "hours": 1.2736, "text": "Code Invaders Devlog - Added Tiny Particles Explosions when enemies die!"}, {"post_id": 35851, "ts": "2026-07-27T15:42:09Z", "hours": 0.7928, "text": "Added the ImportError Enemy: With high health , but extremely slow speed. This enemy periodically creates regular enemies every few seconds."}, {"post_id": 35789, "ts": "2026-07-27T13:22:38Z", "hours": 0.7811, "text": "Added MemoryError Enemies that have high health, but move very slowly. You cannot hit other enemies until you destroy them. (They’re the ones at the very top)"}, {"post_id": 35763, "ts": "2026-07-27T12:21:28Z", "hours": 5.0053, "text": "Code Invaders Devlog 5 - Added Upgrade Cards which you get after each wave. They upgrade some of your stats, like Damage, Speed, Cooldown, and Tower Health."}, {"post_id": 35289, "ts": "2026-07-26T16:29:01Z", "hours": 0.6192, "text": "Code Invaders Devlog 4 - Added the File Towers you protect from bugs. They take damage when collided with…"}, {"post_id": 35251, "ts": "2026-07-26T15:36:37Z", "hours": 0.8811, "text": "Code Invaders Devlog 3 - Added enemies to shoot"}, {"post_id": 35172, "ts": "2026-07-26T12:58:51Z", "hours": 0.5289, "text": "Code Invaders Devlog 2 - I added shooting mechanics!"}, {"post_id": 34998, "ts": "2026-07-26T04:36:24Z", "hours": 0.6072, "text": "Code Invaders Devlog 1 - Added Ship Sprite and Movement code"}]...
|
Title: Code Invaders by @RaspberryPi314 | Stardanc Title: Code Invaders by @RaspberryPi314 | Stardance
Devlogs:
Code Invaders Devlog 1 - Added Ship Sprite and Movement code
Code Invaders Devlog 2 - I added shooting mechanics!
Code Invaders Devlog 3 - Added enemies to shoot
Code Invaders Devlog 4 - Added the File Towers you protect from bugs. They take damage when collided with…
Code Invaders Devlog 5 - Added Upgrade Cards which you get after each wave. They upgrade some of your stats, like Damage, Speed, Cooldown, and Tower Health.
Added MemoryError Enemies that have high health, but move very slowly. You cannot hit other enemies until you destroy them. (They’re the ones at the very top)
Added the ImportError Enemy: With high health , but extremely slow speed. This enemy periodically creates regular enemies every few seconds.
Code Invaders Devlog - Added Tiny Particles Explosions when enemies die!
I added the BrokenPipe Enemy… It shoots bullets (the little blue things almost at the bottom) down below that do damage to your ship and files. These enemies are based on real Python Errors
Code Invaders Devlog - Added Start Screen
Trying to Add a Boss - It has extremely high health, doesn’t move down, and there are no files during the boss fight . This will be wave 20, and the bpss will have 3 stages (but what?) It is based off of RecursionError
Added particle explosions when a boss gets hit, but they are smaller to make the shooting feel more responsive. I may add flashing later.
The boss now spawns other smaller enemies from previous stages. It also has 3 attacks , a laser fan, a 3-shot cannon , and a beam from its eyes.
I added 3 new weapons: Double, Shotgun, and Mines. Double shoots 2 bullets at once. Shotgun shoots 5 bullets in a fan that do 50% more Damage, but has a longer cooldown. Mines lays a mine that only activates when enemies are close, and does area damage with 100% more damage. It has the longest cooldown
I added a textbox so I can add a storyline to the game, and the game pauses while the story is playing!
Transitioning from 3 cards at the end of each level into a shop with currency
MULTIPLAYER WORKS !(kind of). The ship movement and laser shots are now synced, but I still need to sync enemies and the shop.
Multiplayer now work 50% after working on the multiplayer for 10 hours and then deleting all of that! I love development!
Ships:
I created a space-invaders themed game with programming elements. The most challenging part was probably creating the start screen and debugging. I am proud of all the enemies , and the power-up cards. You should know that you can play my game in a itch.io browser, but it will probably be best to play on a laptop / monitor....
|
1792882083.3448339
|
1793746083.3448339
|
|
12006
|
Sh’elah by @akiva_yevdayev | Stardance
|
akiva_yevdayev
|
1
|
96.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-27T04:13:30Z", "hours": 96.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "What did I make? I made Sh’elah (shelah.org) — the Torah Encyclopedia, literally. a searchable library of Torah and judaic texts and commentary (all powered by Sefaria’s texts and made to feel easy to use), an AI assistant that answers questions on Jewish law (halachah) by pulling information from primary sources like the Torah and judaic texts instead of just guessing, and the practical stuff people actually need everyday — live prayer times (zmanim), a Hebrew calendar, and how different communities observe different customs. The AI is built to always point you back to your own rabbi for anything that’s actually a different based on community and needs a ruling, and it steps out of the way entirely for anything medical or safety-related, and has safeguards to protect it from answering strange or unrelated questions or from being prompt injected (because we don’t want our site to get hacked lol). The prayer-times/calendar run off of your exact location, and the calendar shows the weekly Torah portion and candle lighting times too. What was challenging for me? Getting the AI to have safeguards, not hallucinate, follow judaic law and texts, and all set up took way longer than I had originally expected. It’s easy to make a chatbot that sounds confident; it’s much harder to make one that cites where an answer actually comes from, doesn’t quietly make things up, and knows when to deflect a question or malicious prompt. I also spent a lot of time on things nobody will ever see directly — locking down who can access what in the database, making sure a runaway request can’t rack up a huge AI bill (because this site is made for the public to be free, and not to make me go broke °~°), keeping the site fast and not-broken in English and Hebrew, light and dark mode, and working/looking well on phone or tablet-sized screens. Giving the AI real tool-use so it reaches for live prayer times/calendar/texts itself was its own project, and I found out at one point my login system and database weren’t even linked correctly, silently breaking database reads/writes (was a pain to fix…). There’s also a bug where the page jumped up by 5-10 chapters at once which I fixed (and have been trying to fix that issue for MONTHS!) What am I proud of? That it actually exists as an actual product and as a solution instead of just an idea living inside someone’s head. Every page has a real link you can share — a specific judaic text, an AI answer, a specific calendar day— and it opens back up exactly the way you left it. The commentary and translations are genuinely fast now (they were super buggy and slow before), the calendar actually gives candle-lighting times and areas in my app where the torah portions are and had a huge glow-up. I also went from 60% test coverage to over 99%, with nearly 4,000 tests passing cleanly. Keep in mind the whole thing was built by myself (yes ofc was built using ai but without that it would’ve taken years to make), end to end, including a real test suite, real security practices, accessibility support, and full legal documentation and copyright license, and not just a prototype held together by hopes and prayers. What should people know so they can test it? Try asking it an actual halacha question (but since most of you guys aren’t Jewish ask it a question you’ve had on the old testament or on Judaism maybe) that you may have wondered about and see if it gives you a real answer with sources instead of a vague and incorrect answer. Open a Torah portion and look at commentaries or a translation of a specific word. Switch it into Hebrew and make sure nothing breaks. Try it on your phone. See the prayer times based on location. Look at the calendar. Go bananas! Just know that if there is any issue at all, contact me through my email [email protected] and I’ll try my best to fix it as soon as I can.", "repo": "https://github.com/akivayevdayev-debug/Shelah", "demo": "https://shelah.org"}]...
|
[{"post_id": 74270, "ts": "202 [{"post_id": 74270, "ts": "2026-09-27T03:25:18Z", "hours": 4.7697, "text": "Sh’elah — Devlog 8 WE FINALLY SHIP TODAY!!!!!!!!!!!!!!!!!!!!!!!! Over the past week or so, I had… Redesigned parts of the ai look again so that it doesn’t look like ai slop :) Gave the whole site links and web addresses whic h means any page or ai chat or settings u have and wanna give someone the link they can open to the same place as you (major issue fixed!). Added /signin and /profile as real pages that layer on top of whatever you’re looking at, so signing in from a legal or help page brings you right back where you started. Found and fixed why the AI sometimes gave no answer at all: the sign-in check between the site and the database was rejecting valid logins, which quietly broke saving your conversations and preferences. (YAY MORE BUGS FIXED) Sped up word/translation lookups. A word Sefaria didn’t recognize used to try several spellings against the dictionary and then several more against translation, one at a time — now it takes a second (maybe 2 if needs more sources). Fixed animation and fading issues, as well as issues when switching reading layout, switching commentary verses, and jumping to a cited passage (which, it turned out, didn’t actually highlight anything yet). Fixed the reader losing its place. Scrolling to load more text, or loading a previous chapter, could silently jump the page’s address to the wrong chapter. It now tracks what you’re actually reading, not just whichever paragraph happened to load first. (I’VE BEEN TRYNA FIX THAT ISSUE FOR MONTHS!) Cleaned up account and privacy details: a smaller profile menu, a delete-account warning that isn’t half-pink in dark mode, and your data export now actually includes your AI chats. Fixed a leftover database error that had been showing up in the logs from a migrations table that never existed — it’s created properly now, with the right access rules attached. WE SHIP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"}, {"post_id": 73745, "ts": "2026-09-25T20:42:53Z", "hours": 12.4672, "text": "Sh’elah — Devlog 7 — WE SHIP THIS WEEK!!!!! Over the past week or so, I had… Gave every page of the site its own real address. Any text, prayer, calendar day or AI answer now has its own link that opens straight to that page, even on a refresh. Old-style links still work too. Made AI answers shareable. Anyone can hit Copy Link to send a specific answer, or open it as its own page, and it stays out of search engines unless it’s meant to be public. Went through a 15-item punch list end to end: infinite scroll no longer jumps around, the commentary sidebar loads way faster and lighter, various calendar issues are fixed, parashah and commentary names are now accurate and properly ranked, community pages have full Hebrew translations, the header date now follows your actual location, loading spinners recover on their own when a connection drops, and implemented a bunch of Hebrew translate and bolding fixes. Completely Redid EVERYTHING about the AI: Redid the AI window’s entrance animation so it grows out of the Ask button on desktop instead of just popping in, and rises as a proper sheet on phones. Moved the Ask button onto the phone’s top bar instead of hiding it behind a Search tap, and gave the bottom tabs real icons above their labels with even spacing. Added a new ai small window, new ai fullscreen window, and new ai chat sharing links that legitimately work. Polished motion sitewide: screens fade up, buttons get a proper hover/press/focus feel, every emoji became a matching icon, and calendar hover states got fixed instead of going backwards (the close button used to lighten on hover, now it darkens like everything else). Built a real holiday detail card for the calendar, with accurate clock times and links straight into the reader. Fixed prayer and reader text losing its bold and italic formatting when pulled from the source library. Fixed the reader jumping around when loading earlier text, and gave it a slimmer bar with commentary that preloads before you tap it. Locked down the AI’s spending: the plain (non-agentic) chat route was quietly skipping the budget check, and a bug in the model-calling code could leak the API key. Both are fixed, and every path now respects the daily budget. Added a circuit breaker to the rate limiter so a database lag can’t take the whole site down with it, and made sure static files are never rate-limited. Cleared out SonarCloud’s entire backlog again: dead code removed, regexes hardened against slowdowns, and a chunk of new tests written along the way. Made Turnstile (the invisible spam check) actually invisible instead of showing its widget. Reconciled a stack of parallel work — calendar icons, i18n, reader fixes, security fixes — that had drifted across a few branches, merged clean. Let me know if there is anything y’all wanna see on my site in the future p.s. WE ARE ALMOST SHIPPED, but i still want those hours to count so this is not the last devlog."}, {"post_id": 70879, "ts": "2026-09-19T22:38:15Z", "hours": 11.8378, "text": "Sh’elah — Devlog 6 Over the past week or so, I had… Fixed certain dark mode values so they match the overall theme of the site. Added an ai symbol in the shape of a star and added animations to the searchbar when the ai is thinking, adding an ai feedback button, and fixed spacing and other issues with the ai answers. Added a commentary button to the reader’s top bar to show people how to use it Fixed zmanim (prayer/holiday times) on Holidays and fast days, added fast start and end times, and gave the AI Hebrew-date math tools. Finalized the legal pages with real operator info, registered a DMCA agent, and added an age confirmation. Went through every SonarCloud finding and the quality gate now passes, with the security and reliability ratings both at A. Wrote a big batch of new tests. Coverage went from 60% to about 84% overall, and all 3517 tests (yes ik its a lot of tests) pass cleanly. (yes somehow it was 60% before when I explicitly added tests for 93% coverage · ~ ·) Rotated the leaked Gemini key and cleaned it out of the repo history. (correcty this time), and merged two drifting copies of the code, so shared pieces like the AI answer builder now live in one place. Rewrote the README, added a changelog, documented every environment variable, and regenerated the database docs from the live schema. Let me know if there is anything y’all wanna see on my site in the future p.s. shipping v1.00 in a day or two!!!!!! FINALLY!!!!! (This may take longer than two days but hopefully not!)"}, {"post_id": 68421, "ts": "2026-09-15T02:54:39Z", "hours": 14.2753, "text": "Sh’elah — Devlog 5 Over the past week or so, I had… Gave the AI real tool-use, allowing it to get live prayer times, calendar dates, and texts as it needs them, instead of having everything be pre-loaded at each request. Finalized the legal pages and filed my site for DMCA Copyright protection for 3 years. Added self-serve privacy controls, where you can now export or delete your own account and data yourself. Added a feedback button on AI answers so people can flag bad ones directly. Added accessibility keyboard/screen-reader support along with their appropriate tests in CI. Fixed a security issue where a malicious AI-cited link could execute code, and added a bot-check in front of the AI endpoint to cut down on abuse. Fixed the caching bug from last devlog this time; pages get served from cache properly now instead of requesting from the server on every load. Fixed a bunch of small little annoying bugs like the page jumping back while scrolling, the wrong section getting highlighted, calendar color glitches, and animations not loading. Fixed a security-check script that had quietly been failing every single scheduled run for over a week. Spent alot of time simplifying complex functions across the codebase to make it more reliable. Let me know if there is anything y’all wanna see on my site in the future p.s. getting closer to that v1.00 site goal every day — planning on achieving it next week!"}, {"post_id": 61981, "ts": "2026-09-05T05:45:36Z", "hours": 10.3361, "text": "Sh’elah — Devlog 4 Over the past week or so, I had… Fixed an issue with RLS in Supabase so that one user doesn’t see another user’s personal info, as well as security issues with Vercel and Clerk (Which was a pain to fix :<) Found out my login system and database weren’t linked to each other correctly, which was breaking authenticated reads/writes, and fixed it Added an ai usage tracker and fixed old usage records so the spending log is correct, and so I don’t go broke when other people use my site’s ai My webhook (discord error bot) was malfunctioning (and still kinda is in clerk :<) and no longer is! YAY MORE ERRORS FOR ME! (at least I’ll know why they happen :|) Fixed a bug where the site was incorrectly caching files in browsers, making things slower and more expensive (yay less money to spend!!!!!) Ran accessibility tests and fixed any issues they found, and made my site more ready for releasing v1.00! Removed old files Fixed some legal documentation issues (like my Privacy Policy and ToS) so I don’t get sued!!! Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out."}, {"post_id": 55408, "ts": "2026-08-27T06:56:47Z", "hours": 10.6378, "text": "Sh’elah — Devlog 3 Over the past week or so, I had… Fixed a bug where a malformed cache config could crash the whole app on startup. Split a file that handled AI question-answering into smaller, cleaner, more compact files, and added tests to make sure that both versions (one for gemini and one for claude) always answered the same way with the same guardrails. Sped up busy/resource heavy pages (library, prayers, texts, daily study, and the calendar lookup) by adding a shared caching layer, so they don’t request the database on every single request anymore. Added rate limiting across the whole site instead of having it scattered in different places. Cleaned up a batch of files that were referenced in the code which was uncommitted and caused boot errors. Simplified a few functions that had been made too complex to safely maintain. Sped up cold starts by delaying AI library imports until they’re actually needed. Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out."}, {"post_id": 51996, "ts": "2026-08-22T00:35:52Z", "hours": 9.3681, "text": "Sh’elah — Devlog 2 Over the past 9 hours or so, I had… Removed a leftover routing rule in Vercel that was returning a 404 error in my production site. Added a server-side daily budget per user, so if someone goes past it and heavily uses the AI past what’s normal, they get rate limited and can’t spam multiple requests at once. Also fixed an issue where AI usage was being reported as $0 when it wasn’t. Updated my site’s README.md on GitHub, fixed a license mismatch, and added a CONTRIBUTING.md and a code of conduct. Old logs and history get deleted on a schedule now, so trash doesn’t build up over time. Built a dark-mode accessibility checker and fixed contrast issues. Also integrated circuit breakers so when an external resource fails the site doesn’t crash. Added About/Help/glossary pages, a sitemap, a feedback widget, and analytics that you can opt into. Added CI checks and Vercel Speed Insights to track loading times. Swapped the GPS permission for zmanim (prayer times) based on location to cookie/IP-based location instead. Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out."}, {"post_id": 49112, "ts": "2026-08-17T18:53:44Z", "hours": 22.1481, "text": "Sh’elah — First Devlog: I’ve been working on Sh’elah for a while now and finally uploaded it here. It’s a Jewish learning app that combines a searchable Torah library (similar to Sefaria) with an AI tool designed to actually answer your halacha questions. Instead of just throwing related sources at you that don’t end up answering the question, it walks you through the actual answer, explains the reasoning, cites the sources, and tailors everything based on your community’s specific customs. What it does today Answers questions across any area of Jewish law using primary sources rather than generic guesses. Allows you to search the library with customs broken out by community (Ashkenazi, Sefardi, Teimani, and others). Calculates live zmanim (prayer times) and a Hebrew calendar based on your exact location. Ends every answer with a clear reminder: this is for learning purposes, not an official ruling, and real questions should always go to your rabbi. It works right now, but it’s still in the early stages, so I want to be upfront about what still needs work before calling it a complete release. Making the AI reach for things, not just recite them Right now, the AI only knows what gets put into the prompt ahead of time. I am working on moving it toward real tool use so it can pull zmanim, calendar dates, commentaries, and community customs dynamically as needed. Judaic texts and laws will always remain the main priority, with web searching kept strictly as a last resort. Getting the safety layer right (in progress) Halacha touches sensitive material, and I want to make sure a younger user doesn’t receive graphic content when the real answer should simply be “ask your rabbi for details.” Any queries related to medical issues, mental health, or abuse will automatically route to real professional resources rather than generating an AI ruling. Behind-the-scenes technical updates Breaking down a backend file that got way too large so the code is easier to maintain and debug. Securing the caching layer so it handles concurrent load safely. Adding circuit breakers to prevent a third-party outage from crashing the whole platform. What needs to happen before full launch Verifying every feature works properly while keeping the user experience smooth and simple. Completing a thorough security review (already finished). Setting up error tracking and rate limiting to protect the site from abuse. Performing a full accessibility audit. Building this isn’t going to be easy, and the order of these steps will probably shift around. However, this is the general direction of the project, and I’ll share more updates as new features roll out."}]...
|
Title: Sh’elah by @akiva_yevdayev | Stardance
Dev Title: Sh’elah by @akiva_yevdayev | Stardance
Devlogs:
Sh’elah — First Devlog: I’ve been working on Sh’elah for a while now and finally uploaded it here. It’s a Jewish learning app that combines a searchable Torah library (similar to Sefaria) with an AI tool designed to actually answer your halacha questions. Instead of just throwing related sources at you that don’t end up answering the question, it walks you through the actual answer, explains the reasoning, cites the sources, and tailors everything based on your community’s specific customs. What it does today Answers questions across any area of Jewish law using primary sources rather than generic guesses. Allows you to search the library with customs broken out by community (Ashkenazi, Sefardi, Teimani, and others). Calculates live zmanim (prayer times) and a Hebrew calendar based on your exact location. Ends every answer with a clear reminder: this is for learning purposes, not an official ruling, and real questions should always go to your rabbi. It works right now, but it’s still in the early stages, so I want to be upfront about what still needs work before calling it a complete release. Making the AI reach for things, not just recite them Right now, the AI only knows what gets put into the prompt ahead of time. I am working on moving it toward real tool use so it can pull zmanim, calendar dates, commentaries, and community customs dynamically as needed. Judaic texts and laws will always remain the main priority, with web searching kept strictly as a last resort. Getting the safety layer right (in progress) Halacha touches sensitive material, and I want to make sure a younger user doesn’t receive graphic content when the real answer should simply be “ask your rabbi for details.” Any queries related to medical issues, mental health, or abuse will automatically route to real professional resources rather than generating an AI ruling. Behind-the-scenes technical updates Breaking down a backend file that got way too large so the code is easier to maintain and debug. Securing the caching layer so it handles concurrent load safely. Adding circuit breakers to prevent a third-party outage from crashing the whole platform. What needs to happen before full launch Verifying every feature works properly while keeping the user experience smooth and simple. Completing a thorough security review (already finished). Setting up error tracking and rate limiting to protect the site from abuse. Performing a full accessibility audit. Building this isn’t going to be easy, and the order of these steps will probably shift around. However, this is the general direction of the project, and I’ll share more updates as new features roll out.
Sh’elah — Devlog 2 Over the past 9 hours or so, I had… Removed a leftover routing rule in Vercel that was returning a 404 error in my production site. Added a server-side daily budget per user, so if someone goes past it and heavily uses the AI past what’s normal, they get rate limited and can’t spam multiple requests at once. Also fixed an issue where AI usage was being reported as $0 when it wasn’t. Updated my site’s README.md on GitHub, fixed a license mismatch, and added a CONTRIBUTING.md and a code of conduct. Old logs and history get deleted on a schedule now, so trash doesn’t build up over time. Built a dark-mode accessibility checker and fixed contrast issues. Also integrated circuit breakers so when an external resource fails the site doesn’t crash. Added About/Help/glossary pages, a sitemap, a feedback widget, and analytics that you can opt into. Added CI checks and Vercel Speed Insights to track loading times. Swapped the GPS permission for zmanim (prayer times) based on location to cookie/IP-based location instead. Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out.
Sh’elah — Devlog 3 Over the past week or so, I had… Fixed a bug where a malformed cache config could crash the whole app on startup. Split a file that handled AI question-answering into smaller, cleaner, more compact files, and added tests to make sure that both versions (one for gemini and one for claude) always answered the same way with the same guardrails. Sped up busy/resource heavy pages (library, prayers, texts, daily study, and the calendar lookup) by adding a shared caching layer, so they don’t request the database on every single request anymore. Added rate limiting across the whole site instead of having it scattered in different places. Cleaned up a batch of files that were referenced in the code which was uncommitted and caused boot errors. Simplified a few functions that had been made too complex to safely maintain. Sped up cold starts by delaying AI library imports until they’re actually needed. Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out.
Sh’elah — Devlog 4 Over the past week or so, I had… Fixed an issue with RLS in Supabase so that one user doesn’t see another user’s personal info, as well as security issues with Vercel and Clerk (Which was a pain to fix :<) Found out my login system and database weren’t linked to each other correctly, which was breaking authenticated reads/writes, and fixed it Added an ai usage tracker and fixed old usage records so the spending log is correct, and so I don’t go broke when other people use my site’s ai My webhook (discord error bot) was malfunctioning (and still kinda is in clerk :<) and no longer is! YAY MORE ERRORS FOR ME! (at least I’ll know why they happen :|) Fixed a bug where the site was incorrectly caching files in browsers, making things slower and more expensive (yay less money to spend!!!!!) Ran accessibility tests and fixed any issues they found, and made my site more ready for releasing v1.00! Removed old files Fixed some legal documentation issues (like my Privacy Policy and ToS) so I don’t get sued!!! Let me know if there is anything y’all wanna see on my site in the future p.s. I’m planning a huge commit soon announcing version 1.00 of my website so if you haven’t seen my first devlog announcing that, go check it out.
Sh’elah — Devlog 5 Over the past week or so, I had… Gave the AI real tool-use, allowing it to get live prayer times, calendar dates, and texts as it needs them, instead of having everything be pre-loaded at each request. Finalized the legal pages and filed my site for DMCA Copyright protection for 3 years. Added self-serve privacy controls, where you can now export or delete your own account and data yourself. Added a feedback button on AI answers so people can flag bad ones directly. Added accessibility keyboard/screen-reader support along with their appropriate tests in CI. Fixed a security issue where a malicious AI-cited link could execute code, and added a bot-check in front of the AI endpoint to cut down on abuse. Fixed the caching bug from last devlog this time; pages get served from cache properly now instead of requesting from the server on every load. Fixed a bunch of small little annoying bugs like the page jumping back while scrolling, the wrong section getting highlighted, calendar color glitches, and animations not loading. Fixed a security-check script that had quietly been failing every single scheduled run for over a week. Spent alot of time simplifying complex functions across the codebase to make it more reliable. Let me know if there is anything y’all wanna see on my site in the future p.s. getting closer to that v1.00 site goal every day — planning on achieving it next week!
Sh’elah — Devlog 6 Over the past week or so, I had… Fixed certain dark mode values so they match the overall theme of the site. Added an ai symbol in the shape of a star and added animations to the searchbar when the ai is thinking, adding an ai feedback button, and fixed spacing and other issues with the ai answers. Added a commentary button to the reader’s top bar to show people how to use it Fixed zmanim (prayer/holiday times) on Holidays and fast days, added fast start and end times, and gave the AI Hebrew-date math tools. Finalized the legal pages with real operator info, registered a DMCA agent, and added an age confirmation. Went through every SonarCloud finding and the quality gate now passes, with the security and reliability ratings both at A. Wrote a big batch of new tests. Coverage went from 60% to about 84% overall, and all 3517 tests (yes ik its a lot of tests) pass cleanly. (yes somehow it was 60% before when I explicitly added tests for 93% coverage · ~ ·) Rotated the leaked Gemini key and cleaned it out of the repo history. (correcty this time), and merged two drifting copies of the code, so shared pieces like the AI answer builder now live in one place. Rewrote the README, added a changelog, documented every environment variable, and regenerated the database docs from the live schema. Let me know if there is anything y’all wanna see on my site in the future p.s. shipping v1.00 in a day or two!!!!!! FINALLY!!!!! (This may take longer than two days but hopefully not!)
Sh’elah — Devlog 7 — WE SHIP THIS WEEK!!!!! Over the past week or so, I had… Gave every page of the site its own real address. Any text, prayer, calendar day or AI answer now has its own link that opens straight to that page, even on a refresh. Old-style links still work too. Made AI answers shareable. Anyone can hit Copy Link to send a specific answer, or open it as its own page, and it stays out of search engines unless it’s meant to be public. Went through a 15-item punch list end to end: infinite scroll no longer jumps around, the commentary sidebar loads way faster and lighter, various calendar issues are fixed, parashah and commentary names are now accurate and properly ranked, community pages have full Hebrew translations, the header date now follows your actual location, loading spinners recover on their own when a connection drops, and implemented a bunch of Hebrew translate and bolding fixes. Completely Redid EVERYTHING about the AI: Redid the AI window’s entrance animation so it grows out of the Ask button on desktop instead of just popping in, and rises as a proper sheet on phones. Moved the Ask button onto the phone’s top bar instead of hiding it behind a Search tap, and gave the bottom tabs real icons above their labels with even spacing. Added a new ai small window, new ai fullscreen window, and new ai chat sharing links that legitimately work. Polished motion sitewide: screens fade up, buttons get a proper hover/press/focus feel, every emoji became a matching icon, and calendar hover states got fixed instead of going backwards (the close button used to lighten on hover, now it darkens like everything else). Built a real holiday detail card for the calendar, with accurate clock times and links straight into the reader. Fixed prayer and reader text losing its bold and italic formatting when pulled from the source library. Fixed the reader jumping around when loading earlier text, and gave it a slimmer bar with commentary that preloads before you tap it. Locked down the AI’s spending: the plain (non-agentic) chat route was quietly skipping the budget check, and a bug in the model-calling code could leak the API key. Both are fixed, and every path now respects the daily budget. Added a circuit breaker to the rate limiter so a database lag can’t take the whole site down with it, and made sure static files are never rate-limited. Cleared out SonarCloud’s entire backlog again: dead code removed, regexes hardened against slowdowns, and a chunk of new tests written along the way. Made Turnstile (the invisible spam check) actually invisible instead of showing its widget. Reconciled a stack of parallel work — calendar icons, i18n, reader fixes, security fixes — that had drifted across a few branches, merged clean. Let me know if there is anything y’all wanna see on my site in the future p.s. WE ARE ALMOST SHIPPED, but i still want those hours to count so this is not the last devlog.
Sh’elah — Devlog 8 WE FINALLY SHIP TODAY!!!!!!!!!!!!!!!!!!!!!!!! Over the past week or so, I had… Redesigned parts of the ai look again so that it doesn’t look like ai slop :) Gave the whole site links and web addresses whic h means any page or ai chat or settings u have and wanna give someone the link they can open to the same place as you (major issue fixed!). Added /signin and /profile as real pages that layer on top of whatever you’re looking at, so signing in from a legal or help page brings you right back where you started. Found and fixed why the AI sometimes gave no answer at all: the sign-in check between the site and the database was rejecting valid logins, which quietly broke saving your conversations and preferences. (YAY MORE BUGS FIXED) Sped up word/translation lookups. A word Sefaria didn’t recognize used to try several spellings against the dictionary and then several more against translation, one at a time — now it takes a second (maybe 2 if needs more sources). Fixed animation and fading issues, as well as issues when switching reading layout, switching commentary verses, and jumping to a cited passage (which, it turned out, didn’t actually highlight anything yet). Fixed the reader losing its place. Scrolling to load more text, or loading a previous chapter, could silently jump the page’s address to the wrong chapter. It now tracks what you’re actually reading, not just whichever paragraph happened to load first. (I’VE BEEN TRYNA FIX THAT ISSUE FOR MONTHS!) Cleaned up account and privacy details: a smaller profile menu, a delete-account warning that isn’t half-pink in dark mode, and your data export now actually includes your AI chats. Fixed a leftover database error that had been showing up in the logs from a migrations table that never existed — it’s created properly now, with the right access rules attached. WE SHIP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Ships:
What did I make? I made Sh’elah (shelah.org) — the Torah Encyclopedia, literally. a searchable library of Torah and judaic texts and commentary (all powered by Sefaria’s texts and made to feel easy to use), an AI assistant that answers questions on Jewish law (halachah) by pulling information from primary sources like the Torah and judaic texts instead of just guessing, and the practical stuff people actually need everyday — live prayer times (zmanim), a Hebrew calendar, and how different communities observe different customs. The AI is built to always point you back to your own rabbi for anything that’s actually a different based on community and needs a ruling, and it steps out of the way entirely for anything medical or safety-related, and has safeguards to protect it from answering strange or unrelated questions or from being prompt injected (because we don’t want our site to get hacked lol). The prayer-times/calendar run off of your exact location, and the calendar shows the weekly Torah portion and candle lighting times too. What was challenging for me? Getting the AI to have safeguards, not hallucinate, follow judaic law and texts, and all set up took way longer than I had originally expected. It’s easy to make a chatbot that sounds confident; it’s much harder to make one that cites where an answer actually comes from, doesn’t quietly make things up, and knows when to deflect a question or malicious prompt. I also spent a lot of time on things nobody will ever see directly — locking down who can access what in the database, making sure a runaway request can’t rack up a huge AI bill (because this site is made for the public to be free, and not to make me go broke °~°), keeping the site fast and not-broken in English and Hebrew, light and dark mode, and working/looking well on phone or tablet-sized screens. Giving the AI real tool-use so it reaches for live prayer times/calendar/texts itself was its own project, and I found out at one point my login system and database weren’t even linked correctly, silently breaking database reads/writes (was a pain to fix…). There’s also a bug where the page jumped up by 5-10 chapters at once which I fixed (and have been trying to fix that issue for MONTHS!) What am I proud of? That it actually exists as an actual product and as a solution instead of just an idea living inside someone’s head. Every page has a real link you can share — a specific judaic text, an AI answer, a specific calendar day— and it opens back up exactly the way you left it. The commentary and translations are genuinely fast now (they were super buggy and slow before), the calendar actually gives candle-lighting times and areas in my app where the torah portions are and had a huge glow-up. I also went from 60% test coverage to over 99%, with nearly 4,000 tests passing cleanly. Keep in mind the whole thing was built by myself (yes ofc was built using ai but without that it would’ve taken years to make), end to end, including a real test suite, real security practices, accessibility support, and full legal documentation and copyright license, and not just a prototype held together by hopes and prayers. What should people know so they can test it? Try asking it an actual halacha question (but since most of you guys aren’t Jewish ask it a question you’ve had on the old testament or on Judaism maybe) that you may have wondered about and see if it gives you a real answer with sources instead of a vague and incorrect answer. Open a Torah portion and look at commentaries or a translation of a specific word. Switch it into Hebrew and make sure nothing breaks. Try it on your phone. See the prayer times based on location. Look at the calendar. Go bananas! Just know that if there is any issue at all, contact me through my email [email protected] and I’ll try my best to fix it as soon as I can....
|
1793004486.430641
|
1793090886.430641
|
|
27556
|
Skysync by @bartoszkasyna | Stardance
|
bartoszkasyna
|
1
|
96.0
|
880
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-11T20:21:44Z", "hours": 96.0, "multiplier": 18.26, "payout": 880, "blessing": "neutral", "text": "Privacy-first encrypted cloud storage for securely uploading, organizing, previewing, and sharing files. Built with React, TypeScript, and Rust. Desktop view recommended :)", "repo": "https://github.com/B4rtekk1/SkysyncR", "demo": "https://skysync.dev"}]...
|
[{"post_id": 40286, "ts": "202 [{"post_id": 40286, "ts": "2026-08-03T18:30:52Z", "hours": 2.0733, "text": "Updated mobile UI. cant update demo link so here: https://skysync.dev"}, {"post_id": 39470, "ts": "2026-08-02T13:15:45Z", "hours": 5.5069, "text": "Made skysync work with custom domain and SSL certificate. Updated security and UI a little. Updated docker files. Now ready to ship!"}, {"post_id": 38963, "ts": "2026-08-01T16:13:13Z", "hours": 3.6919, "text": "Added Recent and important page. Added folder soft deletion. Added ransomware detector(I hope). Added word files preview. Added sounds files preview."}, {"post_id": 38423, "ts": "2026-07-31T19:44:14Z", "hours": 5.8661, "text": "I didnt focus on UI as I said in previous devlog, I decided to add all functionalities first and then adjust UI. So I improved security page. I also updated backend to be more secure. Two or three devlogs more and I finish functionalities, then i am going on one week holiday. I’m targeting at 15-18 August to deploy"}, {"post_id": 37863, "ts": "2026-07-30T20:46:10Z", "hours": 6.7542, "text": "Improved main page UI. Added security page. Added limits while creating ZIP. Updated settings page. Fixed UI bugs.Now I will focus on mobile view"}, {"post_id": 37213, "ts": "2026-07-29T19:17:10Z", "hours": 5.9672, "text": "Updated dashboard UI a little. Updated settings page. Added download checksum, session managment resumable file upload. Added Typescript syntax. Added c/c++/cuda hihjlighter and syntax."}, {"post_id": 35937, "ts": "2026-07-27T18:20:32Z", "hours": 4.0675, "text": "Successfully dockerized whole aplication"}, {"post_id": 33039, "ts": "2026-07-22T16:26:58Z", "hours": 5.0569, "text": "Updated typescript highlighter. Added better files mobility - folder tree view. Drag & drop files into folders. Pausable/Resumable file upload."}, {"post_id": 32418, "ts": "2026-07-21T16:22:56Z", "hours": 4.7278, "text": "Added typescript highlight support. Now insted of loading placeholder images are blured. Improved UI/UX. Updated mobile support. Fixed bug and vulnelabirity"}, {"post_id": 30875, "ts": "2026-07-18T20:36:51Z", "hours": 4.3769, "text": "Added python highlighter with keyword and variables syntax suggestion. Added more tests."}, {"post_id": 30346, "ts": "2026-07-17T20:23:02Z", "hours": 5.5833, "text": "Added custom nof found page. Updated security settings. Added tests. Added OpenAPI specs."}, {"post_id": 29144, "ts": "2026-07-15T20:33:40Z", "hours": 2.5011, "text": "Added create file modal with extension based editor. Added backend support for some features. Added calendar."}, {"post_id": 28969, "ts": "2026-07-15T16:19:07Z", "hours": 2.3747, "text": "Added link expiration date, added file download limit. Added folder description. Improved user privacy"}, {"post_id": 28784, "ts": "2026-07-15T09:02:28Z", "hours": 2.2144, "text": "Added file deletion with retention. Updated security and privacy"}, {"post_id": 28375, "ts": "2026-07-14T16:27:05Z", "hours": 3.1672, "text": "Added custom PDF preview with basic function - in file search. Next pdf features in next update"}, {"post_id": 27858, "ts": "2026-07-13T19:12:01Z", "hours": 0.4897, "text": "Added notes attached to files"}, {"post_id": 27819, "ts": "2026-07-13T18:20:22Z", "hours": 2.3033, "text": "Added custom video preview with prebked volume chart. Added info card in file tile."}, {"post_id": 27556, "ts": "2026-07-13T07:42:50Z", "hours": 1.9786, "text": "Added Sort and filter options. IMproved text files preview. Added missing animations."}, {"post_id": 27236, "ts": "2026-07-12T16:56:22Z", "hours": 1.3906, "text": "Added sharing file feature with custom qr code."}, {"post_id": 27191, "ts": "2026-07-12T15:04:17Z", "hours": 2.4408, "text": "Added markdown editing with live preview, added text files edit. Added photos preview, Updated CORS."}, {"post_id": 26818, "ts": "2026-07-11T20:35:00Z", "hours": 2.075, "text": "Added settings page. added photos preview. Fixed depracted features from react. Deleted duplicated lines of code"}, {"post_id": 26691, "ts": "2026-07-11T17:01:30Z", "hours": 4.1953, "text": "Enhanced visuals. Added more animations. Added Groups pagenot yet finished). Added file type icons, memory usgae by file types. Added files upload."}, {"post_id": 25198, "ts": "2026-07-09T08:46:30Z", "hours": 1.0972, "text": "Added favourites tile in nav. Tiles are now draggable."}, {"post_id": 22905, "ts": "2026-07-05T15:26:37Z", "hours": 4.0747, "text": "Added main page placeholder. Security update - resistant to most attacks"}, {"post_id": 20170, "ts": "2026-07-01T18:33:23Z", "hours": 5.2494, "text": "Enhanced signing up and loging in flow. Added verification link sent via email. Added utils files. Added config files. Better files organization."}, {"post_id": 17525, "ts": "2026-06-28T10:44:57Z", "hours": 7.0594, "text": "I added simple welcome page and some rust backend"}]...
|
Title: Skysync by @bartoszkasyna | Stardance
Devl Title: Skysync by @bartoszkasyna | Stardance
Devlogs:
I added simple welcome page and some rust backend
Enhanced signing up and loging in flow. Added verification link sent via email. Added utils files. Added config files. Better files organization.
Added main page placeholder. Security update - resistant to most attacks
Added favourites tile in nav. Tiles are now draggable.
Enhanced visuals. Added more animations. Added Groups pagenot yet finished). Added file type icons, memory usgae by file types. Added files upload.
Added settings page. added photos preview. Fixed depracted features from react. Deleted duplicated lines of code
Added markdown editing with live preview, added text files edit. Added photos preview, Updated CORS.
Added sharing file feature with custom qr code.
Added Sort and filter options. IMproved text files preview. Added missing animations.
Added custom video preview with prebked volume chart. Added info card in file tile.
Added notes attached to files
Added custom PDF preview with basic function - in file search. Next pdf features in next update
Added file deletion with retention. Updated security and privacy
Added link expiration date, added file download limit. Added folder description. Improved user privacy
Added create file modal with extension based editor. Added backend support for some features. Added calendar.
Added custom nof found page. Updated security settings. Added tests. Added OpenAPI specs.
Added python highlighter with keyword and variables syntax suggestion. Added more tests.
Added typescript highlight support. Now insted of loading placeholder images are blured. Improved UI/UX. Updated mobile support. Fixed bug and vulnelabirity
Updated typescript highlighter. Added better files mobility - folder tree view. Drag & drop files into folders. Pausable/Resumable file upload.
Successfully dockerized whole aplication
Updated dashboard UI a little. Updated settings page. Added download checksum, session managment resumable file upload. Added Typescript syntax. Added c/c++/cuda hihjlighter and syntax.
Improved main page UI. Added security page. Added limits while creating ZIP. Updated settings page. Fixed UI bugs.Now I will focus on mobile view
I didnt focus on UI as I said in previous devlog, I decided to add all functionalities first and then adjust UI. So I improved security page. I also updated backend to be more secure. Two or three devlogs more and I finish functionalities, then i am going on one week holiday. I’m targeting at 15-18 August to deploy
Added Recent and important page. Added folder soft deletion. Added ransomware detector(I hope). Added word files preview. Added sounds files preview.
Made skysync work with custom domain and SSL certificate. Updated security and UI a little. Updated docker files. Now ready to ship!
Updated mobile UI. cant update demo link so here: https://skysync.dev
Ships:
Privacy-first encrypted cloud storage for securely uploading, organizing, previewing, and sharing files. Built with React, TypeScript, and Rust. Desktop view recommended :)...
|
1793066071.6694791
|
1793152471.6694791
|
|
34277
|
Gravity simulator by @Krys | Stardance
|
Krys
|
1
|
96.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-31T15:39:24Z", "hours": 96.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a simulator of Gravity between bodies in space. The simulator is fully customizable, so you can change the mass of your objects, their positions and even their shades they left behind. You can create any simulation you want.", "repo": "https://github.com/krysjank/Gravity-simulator", "demo": "https://scratch.mit.edu/projects/1376605963/"}]...
|
[{"post_id": 58940, "ts": "202 [{"post_id": 58940, "ts": "2026-08-31T14:36:41Z", "hours": 5.1353, "text": "Final adjustements, no errors and no bugs. The project is finally ready to be sent. The only things that I had to compromise on were the Save and Load function. Cause due to scratch’s simplicity, it couldn’t subtract all of my variables at once. But nonetheless I was working on this project really hard and I hope it comes out great."}, {"post_id": 58726, "ts": "2026-08-31T08:41:44Z", "hours": 6.1681, "text": "Time flew by so fast last six hours. I’m deep in the Save and Load functions right now. It isn’t just designing buttons and texts, I also need to make sure the buttons react properly and with no error. I created new room for load screen too. If the Save and Load functions will come up right, it’s gonna be huge."}, {"post_id": 54026, "ts": "2026-08-24T19:35:22Z", "hours": 4.0647, "text": "I added two more buttons for Save/Import option, so the user could temporarily save his gravity scenes to show them to someone later. I was also facing problems about resetting the second half of the settings. There was a bug associated with a very early ending of an event that affects other events, resulting in no reaction."}, {"post_id": 42744, "ts": "2026-08-07T16:52:07Z", "hours": 4.1339, "text": "Today, I implemented the option to decide if the x or y positions of each body could be shown. I located it into the second page of settings. It was kind of hard to figure out how to effect six different checkboxes in one single sprite at once. Next time, I’ll add more options for the users.:)))"}, {"post_id": 42532, "ts": "2026-08-07T10:26:54Z", "hours": 4.0836, "text": "Today, I added a new skip button for users that already played gravity simulator. By pressing the button they could skip the tutorial and head on straight to the simulation."}, {"post_id": 42089, "ts": "2026-08-06T17:32:29Z", "hours": 4.1506, "text": "AFTER COUNTLESS HOURS OF DIFFERENT CHANGES, I FINALLY MANAGED TO FIGURE OUT THE SOLUTION FOR THE PROBLEM WITH POSITION MEMORY OF THE BODIES. I redesigned the structure of the code and added some new blocks to it. This major improvement results in a version with literally no bugs in all fields. I can thankfully begin upgrading the settings menu I started making before, because now, I have a solid base for future improvements. THANK GOD I FIGURED IT OUT :)))))))"}, {"post_id": 41870, "ts": "2026-08-06T10:49:36Z", "hours": 4.0669, "text": "My only chance is to go compare different versions of the code, so I’m working on two of the codes at once. The bug that the bodies don’t stay at their positions after returning back to the menu is I think only solvable by separating the code and going through all of it."}, {"post_id": 41388, "ts": "2026-08-05T15:50:18Z", "hours": 4.0739, "text": "Oh daaamn, this session was so annoying!! I was facing crucial bugs in the main simulation, I tried everything just to solve it and I couldn’t figure out why it was happening for 2 whole hours. Then I had a lunchbreak and I returned to programming and I restarted my slow comp…. The program was out of nowhere working and now I came across different problems, at the time I solved the buttons problems. I can’t no more……. :(((((( Once I solve a problem, two others come alive. It’s getting very hard for me."}, {"post_id": 40856, "ts": "2026-08-04T17:27:10Z", "hours": 8.1803, "text": "I succesfully implemented the menu for settings with functioning buttons(pic. 2). It took quite a lot of time to design. And as I was testing the whole application, I came across different bugs, for instance(pic. 1). It happens during the act of pressing the mouse and sliding between both of the next/back buttons and then letting the mouse down. It’s sadly still in process, I can’t figure it out right now."}, {"post_id": 40091, "ts": "2026-08-03T14:05:22Z", "hours": 4.1336, "text": "Today, I added a new button for settings, it comes with animation. I also fixed the problem with the little helper, cause it was lagging sometimes during the usage of it. It was a pain creating the sprocket design by the way ; )"}, {"post_id": 34284, "ts": "2026-07-24T21:12:31Z", "hours": 4.2681, "text": "So, I added the new version of gravity to all of the bodies that could move. The new version’s secret is, that its made in only one column. I also upgraded the small helper hidden in the left high corner. You can see its main code lower. I tested it and it reacts to all of the events it should respond to."}, {"post_id": 33979, "ts": "2026-07-24T11:10:26Z", "hours": 4.2872, "text": "I hope I solved the problem with the bodies sometimes not moving. I invented a new way how to act between pressing space and simulating gravity. The problem that they didn’t move was maybe because the simulation was divided into two programmed groups. One was activated when entering a certain room and the second activated later when pressing space. At least I hope so… I spent a lot of time going through the code and couldn’t find any other solution :("}, {"post_id": 33615, "ts": "2026-07-23T17:51:54Z", "hours": 4.1336, "text": "As I mentioned in previous devlog, I really had to invent a special sprite for each moving body. The shadow under the bodies collided with bodies, so I really didn’t have any different solution. There was also a bug in a cycle. It was about sending messages to other communicators more times than the loop actually looped. So I implemented this code to all of the special sprites for shadows (the code was different every single time)"}, {"post_id": 33428, "ts": "2026-07-23T11:12:06Z", "hours": 4.0333, "text": "I inicialized the gravity for the third body (oh yes, finaly) –> It took me a lot of time, because the more bodies you have, the bigger amount of code is needed. But just as I tried it, I came across a different problem. Bodies collide not only between them, but also with the trajectories of the bodies. This got me really thinking. I might create for each trajectory a sprite."}, {"post_id": 33028, "ts": "2026-07-22T16:09:41Z", "hours": 4.0333, "text": "This time, my programming session was a brutal nightmare. I was trying to fix a very uncomfortable bug and it was hidden in the code below. As more than one sprites had this code, one was experiencing active condition and the second passive. I also upgraded the guide menu with a new design of the mass system."}, {"post_id": 32891, "ts": "2026-07-22T10:49:34Z", "hours": 4.1003, "text": "Now I added a ton of code to another ball, so it could interact with others. I also made a requirement if user wants the ball to move or not, so it could act just as gravity provider or even be attracted by the gravity too. Big changes will happen also to other bodies. See you later : )"}, {"post_id": 32425, "ts": "2026-07-21T16:33:36Z", "hours": 4.2006, "text": "I finally managed to finish the complete guide for users. I added a step-back button so everyone can return to the guide if they missed something. I also added a menu for giving speeds right from the start. It means that the simulations won’t neccesarily be from stable positions. -> I hope I don’t need to mention the bug fixes everyone knows about :"}, {"post_id": 32274, "ts": "2026-07-21T10:42:31Z", "hours": 17.5858, "text": "I recently made a huge jump with the gravity simulator. I added a third body to interact with and I also added kind of a huge guide for the users. The most annoying thing to do was the debugging part. It’s always hard to find the roots of the problem. I hope this simulator ’ll get as much stardust as it can because I´m working hard to get the results I want."}, {"post_id": 27697, "ts": "2026-07-13T14:12:02Z", "hours": 1.5503, "text": "I’m working on simulation between bodies in space. Today, I finally figured out how to do it for the first time. Months before I struggled to perform such a difficult physics simulation. I didn’t really ever understand how dx and dy works. So I tried it and it works pretty well even in scratch."}]...
|
Title: Gravity simulator by @Krys | Stardance
Dev Title: Gravity simulator by @Krys | Stardance
Devlogs:
I’m working on simulation between bodies in space. Today, I finally figured out how to do it for the first time. Months before I struggled to perform such a difficult physics simulation. I didn’t really ever understand how dx and dy works. So I tried it and it works pretty well even in scratch.
I recently made a huge jump with the gravity simulator. I added a third body to interact with and I also added kind of a huge guide for the users. The most annoying thing to do was the debugging part. It’s always hard to find the roots of the problem. I hope this simulator ’ll get as much stardust as it can because I´m working hard to get the results I want.
I finally managed to finish the complete guide for users. I added a step-back button so everyone can return to the guide if they missed something. I also added a menu for giving speeds right from the start. It means that the simulations won’t neccesarily be from stable positions. -> I hope I don’t need to mention the bug fixes everyone knows about :
Now I added a ton of code to another ball, so it could interact with others. I also made a requirement if user wants the ball to move or not, so it could act just as gravity provider or even be attracted by the gravity too. Big changes will happen also to other bodies. See you later : )
This time, my programming session was a brutal nightmare. I was trying to fix a very uncomfortable bug and it was hidden in the code below. As more than one sprites had this code, one was experiencing active condition and the second passive. I also upgraded the guide menu with a new design of the mass system.
I inicialized the gravity for the third body (oh yes, finaly) –> It took me a lot of time, because the more bodies you have, the bigger amount of code is needed. But just as I tried it, I came across a different problem. Bodies collide not only between them, but also with the trajectories of the bodies. This got me really thinking. I might create for each trajectory a sprite.
As I mentioned in previous devlog, I really had to invent a special sprite for each moving body. The shadow under the bodies collided with bodies, so I really didn’t have any different solution. There was also a bug in a cycle. It was about sending messages to other communicators more times than the loop actually looped. So I implemented this code to all of the special sprites for shadows (the code was different every single time)
I hope I solved the problem with the bodies sometimes not moving. I invented a new way how to act between pressing space and simulating gravity. The problem that they didn’t move was maybe because the simulation was divided into two programmed groups. One was activated when entering a certain room and the second activated later when pressing space. At least I hope so… I spent a lot of time going through the code and couldn’t find any other solution :(
So, I added the new version of gravity to all of the bodies that could move. The new version’s secret is, that its made in only one column. I also upgraded the small helper hidden in the left high corner. You can see its main code lower. I tested it and it reacts to all of the events it should respond to.
Today, I added a new button for settings, it comes with animation. I also fixed the problem with the little helper, cause it was lagging sometimes during the usage of it. It was a pain creating the sprocket design by the way ; )
I succesfully implemented the menu for settings with functioning buttons(pic. 2). It took quite a lot of time to design. And as I was testing the whole application, I came across different bugs, for instance(pic. 1). It happens during the act of pressing the mouse and sliding between both of the next/back buttons and then letting the mouse down. It’s sadly still in process, I can’t figure it out right now.
Oh daaamn, this session was so annoying!! I was facing crucial bugs in the main simulation, I tried everything just to solve it and I couldn’t figure out why it was happening for 2 whole hours. Then I had a lunchbreak and I returned to programming and I restarted my slow comp…. The program was out of nowhere working and now I came across different problems, at the time I solved the buttons problems. I can’t no more……. :(((((( Once I solve a problem, two others come alive. It’s getting very hard for me.
My only chance is to go compare different versions of the code, so I’m working on two of the codes at once. The bug that the bodies don’t stay at their positions after returning back to the menu is I think only solvable by separating the code and going through all of it.
AFTER COUNTLESS HOURS OF DIFFERENT CHANGES, I FINALLY MANAGED TO FIGURE OUT THE SOLUTION FOR THE PROBLEM WITH POSITION MEMORY OF THE BODIES. I redesigned the structure of the code and added some new blocks to it. This major improvement results in a version with literally no bugs in all fields. I can thankfully begin upgrading the settings menu I started making before, because now, I have a solid base for future improvements. THANK GOD I FIGURED IT OUT :)))))))
Today, I added a new skip button for users that already played gravity simulator. By pressing the button they could skip the tutorial and head on straight to the simulation.
Today, I implemented the option to decide if the x or y positions of each body could be shown. I located it into the second page of settings. It was kind of hard to figure out how to effect six different checkboxes in one single sprite at once. Next time, I’ll add more options for the users.:)))
I added two more buttons for Save/Import option, so the user could temporarily save his gravity scenes to show them to someone later. I was also facing problems about resetting the second half of the settings. There was a bug associated with a very early ending of an event that affects other events, resulting in no reaction.
Time flew by so fast last six hours. I’m deep in the Save and Load functions right now. It isn’t just designing buttons and texts, I also need to make sure the buttons react properly and with no error. I created new room for load screen too. If the Save and Load functions will come up right, it’s gonna be huge.
Final adjustements, no errors and no bugs. The project is finally ready to be sent. The only things that I had to compromise on were the Save and Load function. Cause due to scratch’s simplicity, it couldn’t subtract all of my variables at once. But nonetheless I was working on this project really hard and I hope it comes out great.
Ships:
I made a simulator of Gravity between bodies in space. The simulator is fully customizable, so you can change the mass of your objects, their positions and even their shades they left behind. You can create any simulation you want....
|
1792982966.7813447
|
1793069366.7813447
|
|
47888
|
Phone Usage by @explodeywolf | Stardance
|
explodeywolf
|
2
|
96.0
|
577
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-17T02:55:14Z", "hours": 45.0, "multiplier": 8.38, "payout": 377, "blessing": "neutral", "text": "I have updated my app! I saw a lot of people wanted analytics - so I have added analytics! If you hover over the pie chart you can see the labels and exact durations. I made everything a lot more memory efficient by rewriting the service that writes the usage data to the disk in kotlin. I added a final display type! It’s a clock(see the hands? That’s how you can tell) I modeled the clock off of the clock in the google clock app. But, I made it in inkscape, then used Flutter’s custom painters to write down everything else! You can even zoom in! If you have an android phone, please try it out! Thank you!", "repo": "https://gitlab.com/peanutplays61/phone-usage", "demo": "https://gitlab.com/peanutplays61/phone-usage/-/releases"}, {"ship_num": 2, "ts": "2026-08-28T21:38:58Z", "hours": 51.0, "multiplier": 6.68, "payout": 200, "blessing": "neutral", "text": "Phone Usage is an android app that displays when you turned on and off your phone, every day. This can be really useful, not just if you want to track your phone usage, and when it happens. You can also use this information to pinpoint what time, for example, you turned off your phone and went to bed. Unfortunately this app is only available as an apk for now, but I am waiting on f-droid to post it on their store! I also made the app pretty customizable, so you can change the color and layout of the app.", "repo": "https://gitlab.com/peanutplays61/phone-usage", "demo": "https://gitlab.com/peanutplays61/phone-usage/-/releases"}]...
|
[{"post_id": 80280, "ts": "202 [{"post_id": 80280, "ts": "2026-10-17T02:51:56Z", "hours": 6.9019, "text": "I’m finally done! I can finally free myself from this app! I made the clock support a fullscreen mode, where viewing landscape is MUCH better. Look at that zoom! Also, I felt like using the red colorscheme for this picture."}, {"post_id": 78782, "ts": "2026-10-11T16:18:04Z", "hours": 9.9444, "text": "Oh boy! I’m trying to add a new display type: A clock! This was my original dream for this project, so I have to make it work! Luckily, flutter comes with a widget that handles zooming, but I had to implement the text, the drawing, the usage info display, the fake hands, and the occlusion culling by myself. I’m almost done! I just need to make it work in the selection page."}, {"post_id": 72829, "ts": "2026-09-23T20:33:45Z", "hours": 3.0381, "text": "I added some quips about your screen time! There’s also a little bit deeper analysis, but you can’t get too much information from just when you turn on and off your phone."}, {"post_id": 71341, "ts": "2026-09-20T17:41:29Z", "hours": 7.4064, "text": "I made a pie chart for usage time! Why did it take me 7 hours? Good question! Unfortunately I couldn’t find a pie chart library on flutter that offered tooltips, so unfortunately I had to make it myself. I use FlCharts for the pie charts, but I do all the stuff for touch highlighting and tooltips. Again. I’ve gotta learn to accept what I have. (the section I’m touching is the one in purple)"}, {"post_id": 69378, "ts": "2026-09-16T22:44:41Z", "hours": 3.9875, "text": "I spent a ton of time making animations for this, but unfortunately I can’t show an animation! But I also finished the dropdown for the analytics :) Now I just need the analytics!"}, {"post_id": 63917, "ts": "2026-09-07T23:17:47Z", "hours": 9.535, "text": "I’m trying to make some analytics! Unfortunately though, I want there to be editable date ranges and that needs a dialog, which means it closes the drop-down. So, I’m making my own. This is the most complex thing I’ve ever done. 5 hours later, this is what I have!"}, {"post_id": 61638, "ts": "2026-09-04T17:05:59Z", "hours": 4.13, "text": "I fixed a bug where the display type wouldn’t save properly! Technically it was an off-by-one error :( I decoded the saved state based off of the index in the array instead of the id, which is what I saved. This is what it was supposed to look like!"}, {"post_id": 56886, "ts": "2026-08-28T21:31:44Z", "hours": 10.1475, "text": "Didn’t go too far over this time! I think I’m done making this app. If anything, I’ll make it a little more performant later, but it’s ready to ship :) I used appmockup to make some pictures for it."}, {"post_id": 52639, "ts": "2026-08-22T21:31:19Z", "hours": 15.3125, "text": "Accidentally went over the 10h limit again! oops! Phone Usage now has settings! You can change the display type of data, as well as the color of the application! Material colors are also supported!!!"}, {"post_id": 47091, "ts": "2026-08-14T18:44:02Z", "hours": 25.1039, "text": "I got my first MVP(minimum viable product)! I’m also trying to get my app uploaded to fdroid, an android open source app store."}]...
|
Title: Phone Usage by @explodeywolf | Stardance
D Title: Phone Usage by @explodeywolf | Stardance
Devlogs:
I got my first MVP(minimum viable product)! I’m also trying to get my app uploaded to fdroid, an android open source app store.
Accidentally went over the 10h limit again! oops! Phone Usage now has settings! You can change the display type of data, as well as the color of the application! Material colors are also supported!!!
Didn’t go too far over this time! I think I’m done making this app. If anything, I’ll make it a little more performant later, but it’s ready to ship :) I used appmockup to make some pictures for it.
I fixed a bug where the display type wouldn’t save properly! Technically it was an off-by-one error :( I decoded the saved state based off of the index in the array instead of the id, which is what I saved. This is what it was supposed to look like!
I’m trying to make some analytics! Unfortunately though, I want there to be editable date ranges and that needs a dialog, which means it closes the drop-down. So, I’m making my own. This is the most complex thing I’ve ever done. 5 hours later, this is what I have!
I spent a ton of time making animations for this, but unfortunately I can’t show an animation! But I also finished the dropdown for the analytics :) Now I just need the analytics!
I made a pie chart for usage time! Why did it take me 7 hours? Good question! Unfortunately I couldn’t find a pie chart library on flutter that offered tooltips, so unfortunately I had to make it myself. I use FlCharts for the pie charts, but I do all the stuff for touch highlighting and tooltips. Again. I’ve gotta learn to accept what I have. (the section I’m touching is the one in purple)
I added some quips about your screen time! There’s also a little bit deeper analysis, but you can’t get too much information from just when you turn on and off your phone.
Oh boy! I’m trying to add a new display type: A clock! This was my original dream for this project, so I have to make it work! Luckily, flutter comes with a widget that handles zooming, but I had to implement the text, the drawing, the usage info display, the fake hands, and the occlusion culling by myself. I’m almost done! I just need to make it work in the selection page.
I’m finally done! I can finally free myself from this app! I made the clock support a fullscreen mode, where viewing landscape is MUCH better. Look at that zoom! Also, I felt like using the red colorscheme for this picture.
Ships:
Phone Usage is an android app that displays when you turned on and off your phone, every day. This can be really useful, not just if you want to track your phone usage, and when it happens. You can also use this information to pinpoint what time, for example, you turned off your phone and went to bed. Unfortunately this app is only available as an apk for now, but I am waiting on f-droid to post it on their store! I also made the app pretty customizable, so you can change the color and layout of the app.
I have updated my app! I saw a lot of people wanted analytics - so I have added analytics! If you hover over the pie chart you can see the labels and exact durations. I made everything a lot more memory efficient by rewriting the service that writes the usage data to the disk in kotlin. I added a final display type! It’s a clock(see the hands? That’s how you can tell) I modeled the clock off of the clock in the google clock app. But, I made it in inkscape, then used Flutter’s custom painters to write down everything else! You can even zoom in! If you have an android phone, please try it out! Thank you!...
|
1793094476.074534
|
1793180876.074534
|
|
68
|
Chaira by @YouSafe | Stardance
|
YouSafe
|
1
|
95.0
|
967
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-17T17:40:42Z", "hours": 95.0, "multiplier": 15.62, "payout": 967, "blessing": "neutral", "text": "project is done :D i hope yall enjoy it, the ui is better than last time and the backend is faster than it was :3 but its running in a twinkpad so ig its not going to be a big factor", "repo": "https://github.com/Y0usaf3/chaira/tree/ui-design", "demo": "https://chaira.y0usaf3.top/dashboard"}]...
|
[{"post_id": 30227, "ts": "202 [{"post_id": 30227, "ts": "2026-07-17T17:16:53Z", "hours": 7.99, "text": "boom, worked on a user page, the table component got polished af and now the project is shippable enought i feel like i write very short devlogs for some reason"}, {"post_id": 27217, "ts": "2026-07-12T16:18:21Z", "hours": 6.4719, "text": "added some context menu :p and also fixed a few issues when updating the cell and now im close to finishing this"}, {"post_id": 22431, "ts": "2026-07-04T21:57:16Z", "hours": 28.9733, "text": "yippee finally made the table component, now you can add fields and add records, and edit stuff, well there is still dropdowns to do extra stuff with fields but its already gud trust!"}, {"post_id": 12497, "ts": "2026-06-20T12:31:38Z", "hours": 20.5597, "text": "ah yes, sorry for not posting devlogs, got a bit too busy, so here it is, the base page, and also fixed the deployement which prob took most of the time, i also worked on the dashboard, still too simple rn but it looks pretty good so far, i will make a simple table page now , not using websocket as supposed to do in my plan but for the sake of shipping now lol"}, {"post_id": 8118, "ts": "2026-06-13T15:31:48Z", "hours": 11.3353, "text": "finally finished most of the backend, now i started making the ui and overall design, im going to deploy this somewhere so ppl can see the updates and try it out :3"}, {"post_id": 3609, "ts": "2026-06-06T16:42:49Z", "hours": 7.9256, "text": "finally added convertion code between all those types, that was hell, but now we can totally rely on the core to handle the type convertion for us ;3"}, {"post_id": 1709, "ts": "2026-06-03T21:25:58Z", "hours": 1.5189, "text": "so i was coding the convertion strategy for SingleLine and LongText, but i was going to accidentally invoke a demon"}, {"post_id": 1068, "ts": "2026-06-02T21:39:25Z", "hours": 5.7936, "text": "was redesigning the Record/field system since it was poorly made, i made a trait for ValueTypes and a macro to easly write convertion code for each type (also hackatime wouldnt track all da time i spent writing on my note book 3:<)"}, {"post_id": 431, "ts": "2026-06-01T20:42:12Z", "hours": 3.8186, "text": "was working on the cache, but it wasnt fast enough so instead we store the sessions in memory in the server directly for a short amount of time, and we refresh from redis, just gonna make sure it actually saves the data :p oh and the speed seems to be very unstable for some reason XD"}, {"post_id": 96, "ts": "2026-05-31T18:13:31Z", "hours": 0.4222, "text": "working on the caching part using redis, its mostly working for the session logic, and will soon use it for other tasks"}]...
|
Title: Chaira by @YouSafe | Stardance
Devlogs:
wo Title: Chaira by @YouSafe | Stardance
Devlogs:
working on the caching part using redis, its mostly working for the session logic, and will soon use it for other tasks
was working on the cache, but it wasnt fast enough so instead we store the sessions in memory in the server directly for a short amount of time, and we refresh from redis, just gonna make sure it actually saves the data :p oh and the speed seems to be very unstable for some reason XD
was redesigning the Record/field system since it was poorly made, i made a trait for ValueTypes and a macro to easly write convertion code for each type (also hackatime wouldnt track all da time i spent writing on my note book 3:<)
so i was coding the convertion strategy for SingleLine and LongText, but i was going to accidentally invoke a demon
finally added convertion code between all those types, that was hell, but now we can totally rely on the core to handle the type convertion for us ;3
finally finished most of the backend, now i started making the ui and overall design, im going to deploy this somewhere so ppl can see the updates and try it out :3
ah yes, sorry for not posting devlogs, got a bit too busy, so here it is, the base page, and also fixed the deployement which prob took most of the time, i also worked on the dashboard, still too simple rn but it looks pretty good so far, i will make a simple table page now , not using websocket as supposed to do in my plan but for the sake of shipping now lol
yippee finally made the table component, now you can add fields and add records, and edit stuff, well there is still dropdowns to do extra stuff with fields but its already gud trust!
added some context menu :p and also fixed a few issues when updating the cell and now im close to finishing this
boom, worked on a user page, the table component got polished af and now the project is shippable enought i feel like i write very short devlogs for some reason
Ships:
project is done :D i hope yall enjoy it, the ui is better than last time and the backend is faster than it was :3 but its running in a twinkpad so ig its not going to be a big factor...
|
1792986922.478417
|
1793073322.478417
|
|
32480
|
Pac-Man by @raslanyossif | Stardance
|
raslanyossif
|
1
|
95.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-27T04:21:15Z", "hours": 95.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a Pac-man but with power ups and more ghosts as you proceed to level up. challenging part was making the maze I struggled a lot. I’m proud that I was able to complete such a project. When you get one of the power ups which is Shield your Pac-man becomes blue, so the ghosts can’t eat you and you can’t eat them. It isn’t a bug I made it that way.", "repo": "https://github.com/Yossifraslan/Pac-Man", "demo": "https://yossifraslan.github.io/Pac-Man/"}]...
|
[{"post_id": 74295, "ts": "202 [{"post_id": 74295, "ts": "2026-09-27T04:15:28Z", "hours": 9.2853, "text": "It’s DEVLOG TIME:» Just pushed a much-needed update to the project! First up, I finally tracked down and killed a frustrating maze error in Level 10 that was completely breaking the game right near the finish line—so the final levels are officially working and playable now. While I was at it, I also took the time to write a proper README. It covers everything from setup instructions to gameplay mechanics, making the codebase a lot more welcoming and less of a black box for anyone who wants to test it out or contribute. Next up is getting some feedback and seeing how quickly people can break it! Also, when you are shielded for the power up, you can’t eat the ghosts."}, {"post_id": 49457, "ts": "2026-08-18T09:45:17Z", "hours": 9.5264, "text": "IT’S DEVLOG TIMEE :»> It’s been a tough few days trying to figure out how to fix the MAZE, but I finally figured out how to do it through A* pathfinding. Fixed all the maps. Which took me so longggg. Also, Fixed speed inconsistency bugs and collision detection to eliminate Pac-Man getting stuck at maze tiles - movement now uses tile-based physics that checks every frame with no edge-case stalls, plus input buffering lets players queue moves ahead for responsive controls. Implemented proper ghost freeze behavior where frozen ghosts stop completely for 5 seconds, stay visible, and remain killable while frozen. Made the Extra Life now work on the screen when you get an Extra life it will update in the UI top middle and see a new Pac-man face get added. On the side of the Maps you can see there is no wall blocking, because now I made it a teleport to the other side."}, {"post_id": 46650, "ts": "2026-08-14T01:56:32Z", "hours": 9.1808, "text": "Fixed all six power-up behaviours this session. Speed boost and double points were already working. The main rework was on shield, freeze, and slow. Shield now stays active until a ghost physically touches the player, when that happens, the ghost turns scared/blue instead of the player dying, and the shield remains active for future hits on a 15-second timer. Freeze keeps ghosts in their normal colour but completely stops their movement for 3 seconds - they’re still killable while frozen. Slow keeps ghosts at their normal appearance but skips movement every other frame, effectively halving their speed for 5 seconds. Also implemented proper ghost spawn behavior. Ghosts now spawn at the center of the maze (on or near the ghost house tiles) and release one by one first ghost after 2 seconds, then one every 3 seconds. While waiting to release they bob up and down inside the house. After death, the release sequence resets so ghosts trickle out again rather than all rushing at once. Pac-Man now spawns at a random open tile at least a third of the maze width away from the centre, so every life and every game starts from a different position. Maze connectivity fix was attempted this session but not completed - some maps still have corridors that can trap the player. Carrying this into the next session"}, {"post_id": 43330, "ts": "2026-08-08T15:07:17Z", "hours": 9.7428, "text": "I fixed up my previous issues with lives resetting to 3 for each level completed as well as start Game taking you back to level 1 rather than starting at the highest level you’ve unlocked. The ghost speed has been halved (from 2px to 1px/frame) which makes everything seem much more balanced with me running around at 60fps! I’ve added a proper pause menu overlay along with options to toggle Music & SFX - I had previously run into an issue where if you paused the game then played again the menu music would keep playing. To fix this I’m keeping track of all active WebAudio Oscillators and automatically stop them whenever we begin gameplay. We’ve added some really nice little touches too! For example, when you die Pac-Man will close his mouth, spin twice and slowly shrink away over 80 frames before disappearing completely. You’ll also get a sweet animation when you spawn growing up from 0 to full size over 40 frames. We originally couldn’t get the death animation working because we’d set our global variable gameActive = false during dying which turned off the entire update loop so I’ve updated Pac-Man’s update method to continue updating even when he’s dying / spawning. Finally, I made sure to make Pac-Man disappear once he dies to ensure no weird visuals happen after respawning. We added a yellow flash on finishing a level. Floating score popups show up every time you eat a ghost. Now there’s an animated HUD that shows your current score. Previously, canvas animations were off due to transform translation applied twice (once during animation and once more when drawing). Now we translate to our sprite’s center before applying any additional transformation."}, {"post_id": 40526, "ts": "2026-08-04T03:32:16Z", "hours": 9.2125, "text": "DEVLOG TIME:> During this session, I incorporated complete mobile compatibility. The directional pad appears automatically on touch devices through (pointer:coarse) through CSS thus eliminating the need for any device detection as it will be shown as soon as the browser detects a device with touch input. Each button utilizes touchstart instead of click , so there is no 300ms tap delay that would make the controls slow or laggy. I also introduced swipe detection on the canvas as a substitute for the directional pad. The minimum distance for swipe detection is 30px, filtering unintended touches and also utilizing the main axis (horizontal or vertical) in order to identify the direction even in case of diagonal swipes. I added responsive CSS for screens smaller than 480px thus allowing the fonts, buttons, and HUD to resize, so no overflowing occurs on small screens. I verified this by checking the local network IP through my mobile, as both devices were connected to the same Wi-Fi network. The InputManager is now capable of working with three types of input in one place - keyboard, touch directional pad, and swipe, all of them leading to a single nextDirection property, which is accessed by the main game loop."}, {"post_id": 39312, "ts": "2026-08-02T06:34:55Z", "hours": 9.3164, "text": "Added an audio system using the WebAudio API. No external sound files everything is generated programmatically using oscillators and gain nodes. Each game event has its sound: a short square wave blip for eating dots a sawtooth drop for eating pellets, a triangle tone for eating ghosts a descending three-note jingle for death and a rising three-note fanfare for level complete. The main menu has a looping chiptune melody. 25 Notes scheduled ahead of time using ctx.currentTime, which avoids timing drift that would happen with repeated setTimeout calls. It loops by scheduling the playthrough when the current one ends. The trickiest part was the browser autoplay policy. Browsers block AudioContext from making sound until the user interacts with the page. The fix was checking ctx.state === suspended on the click and calling ctx.resume() before trying to play anything. Finished power-up effects. Freeze and slow work via frame timers (_frozenTimer _slowTimer) set directly on each monster. The monster update method checks these at the top before doing anything effectively pausing or slowing it without touching core movement logic. Known issue: menu music doesn’t stop immediately when the game starts. There’s a 1-2 overlap before it cuts out. Will fix session along with, in-game sound effects not always triggering. Investigating AudioContext state management across the menu-> game transition."}, {"post_id": 33922, "ts": "2026-07-24T07:11:48Z", "hours": 9.5589, "text": "DEVLOG TIME!!! Added ghosts to the game this session. The ghost AI has 4 behavior types - chaser, ambusher, predictor, and patroller, targeting player based on various positions. Also added A* path finding to have the ghosts go around walls instead of choosing adjacent tiles that are closer to them. Majority of time in this session was spent debugging the movement. It turned out to be a floating-point problem where, when the ghost speed is not divisible by the tile size (20 px), the pixelX % tileSize is never equal to 0 and therefore the alignment function is never called resulting in the ghost moving for 2 px per frame. Fixed this by making the ghost speed fixed at an integer value (2) that is divisible by 20. Eating the power pellet causes the ghost to go into the frighten state which makes the ghost turn blue and move randomly. The player receives 200 points and the respawn timer starts when a ghost in the frighten state is eaten."}, {"post_id": 31207, "ts": "2026-07-19T12:53:56Z", "hours": 9.6542, "text": "WHAT’s NEW:> Devlog Time!!! Got Pac-Man actually moving through the maze this session. Built the Player class with grid-based movement - Pac-Man only changes direction when pixel position is exactly aligned to a tile, which prevents clipping through walls. Added direction queuing so if you press a turn slightly early it still registers when the next tile is reached, making controls feel responsive instead of stiff. Also split out InputManager , CollisionSystem , and UIManager into their own modules. Dot collection works - eating a dot removes it from the array, updates the grid, and increments score. Level completes when all dots and pellets are cleared, with a 500 x level bonus. One thing worth noting from Devlog 2 - the maze connectivity issue. After designing all 10 maze layouts, levels 3-10 had isolated sections where dots were completely unreachable. Wrote a flood-fill validator that BFS traverses from the first dot and counts how many dots are reachable. Then wrote an auto-fixer that finds disconnected sections and carves the shortest Manhattan path between them. All 10 levels now pass with 100% dots reachable."}, {"post_id": 29256, "ts": "2026-07-16T01:45:12Z", "hours": 9.4397, "text": "DEVLOG TIME:> !! I have improved the maze system used in my game, Pac-Man. Originally, I thought of not only using one maze and having a full leveling system. In this, I calculated and created 10 mazes with different sizes, difficulties, and complexity levels. In addition, I modified the class MazeManager in such a way that our game automatically changes levels without requiring a manual change of the mazes. In testing new mazes, I introduced a checking mechanism so that we will know whether our mazes have any unreachable dots. For some reason, it turned out that some parts of the maze were blocked. Maze validation: 195/218 dots reachable Blocked sections were identified. Some of the dots can’t be accessed. Interestingly, the maze looked perfectly okay visually, but the navigation test indicated that some of the areas of my maze were not accessible. At the moment, I plan on fixing the blocked paths and test out each level. I might also change some things later once the game is fully playable and I can properly test the difficulty, such as: maze layouts ghost difficulty level progression number of ghosts/speed scaling Right now the goal is getting the core gameplay working first, then balancing everything afterwards."}, {"post_id": 26506, "ts": "2026-07-11T10:41:25Z", "hours": 9.9617, "text": "I’ve been really busy but here is the first DEVLOG for Pac-man:> I’m planning on doing unique things in this Pac-man it won’t be a normal Pac-man. What I did: Built all 5 screens for the game - main menu, level select, how to play, game screen and game over. No gameplay yet, just the full UI shell. Screen switching works by toggling a single. active class, all screens live in the DOM simultaneously. Biggest challenge was the SVG ghosts. Drew them in pure SVG using and so the shape is defined once and reused everywhere with different colors via a CSS variable –gc. Also styled elements in the How to Play screen to look like actual keyboard keys. Ghost bobbing animation on the menu uses staggered animation-delay so they move in a wave instead of all at once."}]...
|
Title: Pac-Man by @raslanyossif | Stardance
Devlo Title: Pac-Man by @raslanyossif | Stardance
Devlogs:
I’ve been really busy but here is the first DEVLOG for Pac-man:> I’m planning on doing unique things in this Pac-man it won’t be a normal Pac-man. What I did: Built all 5 screens for the game - main menu, level select, how to play, game screen and game over. No gameplay yet, just the full UI shell. Screen switching works by toggling a single. active class, all screens live in the DOM simultaneously. Biggest challenge was the SVG ghosts. Drew them in pure SVG using and so the shape is defined once and reused everywhere with different colors via a CSS variable –gc. Also styled elements in the How to Play screen to look like actual keyboard keys. Ghost bobbing animation on the menu uses staggered animation-delay so they move in a wave instead of all at once.
DEVLOG TIME:> !! I have improved the maze system used in my game, Pac-Man. Originally, I thought of not only using one maze and having a full leveling system. In this, I calculated and created 10 mazes with different sizes, difficulties, and complexity levels. In addition, I modified the class MazeManager in such a way that our game automatically changes levels without requiring a manual change of the mazes. In testing new mazes, I introduced a checking mechanism so that we will know whether our mazes have any unreachable dots. For some reason, it turned out that some parts of the maze were blocked. Maze validation: 195/218 dots reachable Blocked sections were identified. Some of the dots can’t be accessed. Interestingly, the maze looked perfectly okay visually, but the navigation test indicated that some of the areas of my maze were not accessible. At the moment, I plan on fixing the blocked paths and test out each level. I might also change some things later once the game is fully playable and I can properly test the difficulty, such as: maze layouts ghost difficulty level progression number of ghosts/speed scaling Right now the goal is getting the core gameplay working first, then balancing everything afterwards.
WHAT’s NEW:> Devlog Time!!! Got Pac-Man actually moving through the maze this session. Built the Player class with grid-based movement - Pac-Man only changes direction when pixel position is exactly aligned to a tile, which prevents clipping through walls. Added direction queuing so if you press a turn slightly early it still registers when the next tile is reached, making controls feel responsive instead of stiff. Also split out InputManager , CollisionSystem , and UIManager into their own modules. Dot collection works - eating a dot removes it from the array, updates the grid, and increments score. Level completes when all dots and pellets are cleared, with a 500 x level bonus. One thing worth noting from Devlog 2 - the maze connectivity issue. After designing all 10 maze layouts, levels 3-10 had isolated sections where dots were completely unreachable. Wrote a flood-fill validator that BFS traverses from the first dot and counts how many dots are reachable. Then wrote an auto-fixer that finds disconnected sections and carves the shortest Manhattan path between them. All 10 levels now pass with 100% dots reachable.
DEVLOG TIME!!! Added ghosts to the game this session. The ghost AI has 4 behavior types - chaser, ambusher, predictor, and patroller, targeting player based on various positions. Also added A* path finding to have the ghosts go around walls instead of choosing adjacent tiles that are closer to them. Majority of time in this session was spent debugging the movement. It turned out to be a floating-point problem where, when the ghost speed is not divisible by the tile size (20 px), the pixelX % tileSize is never equal to 0 and therefore the alignment function is never called resulting in the ghost moving for 2 px per frame. Fixed this by making the ghost speed fixed at an integer value (2) that is divisible by 20. Eating the power pellet causes the ghost to go into the frighten state which makes the ghost turn blue and move randomly. The player receives 200 points and the respawn timer starts when a ghost in the frighten state is eaten.
Added an audio system using the WebAudio API. No external sound files everything is generated programmatically using oscillators and gain nodes. Each game event has its sound: a short square wave blip for eating dots a sawtooth drop for eating pellets, a triangle tone for eating ghosts a descending three-note jingle for death and a rising three-note fanfare for level complete. The main menu has a looping chiptune melody. 25 Notes scheduled ahead of time using ctx.currentTime, which avoids timing drift that would happen with repeated setTimeout calls. It loops by scheduling the playthrough when the current one ends. The trickiest part was the browser autoplay policy. Browsers block AudioContext from making sound until the user interacts with the page. The fix was checking ctx.state === suspended on the click and calling ctx.resume() before trying to play anything. Finished power-up effects. Freeze and slow work via frame timers (_frozenTimer _slowTimer) set directly on each monster. The monster update method checks these at the top before doing anything effectively pausing or slowing it without touching core movement logic. Known issue: menu music doesn’t stop immediately when the game starts. There’s a 1-2 overlap before it cuts out. Will fix session along with, in-game sound effects not always triggering. Investigating AudioContext state management across the menu-> game transition.
DEVLOG TIME:> During this session, I incorporated complete mobile compatibility. The directional pad appears automatically on touch devices through (pointer:coarse) through CSS thus eliminating the need for any device detection as it will be shown as soon as the browser detects a device with touch input. Each button utilizes touchstart instead of click , so there is no 300ms tap delay that would make the controls slow or laggy. I also introduced swipe detection on the canvas as a substitute for the directional pad. The minimum distance for swipe detection is 30px, filtering unintended touches and also utilizing the main axis (horizontal or vertical) in order to identify the direction even in case of diagonal swipes. I added responsive CSS for screens smaller than 480px thus allowing the fonts, buttons, and HUD to resize, so no overflowing occurs on small screens. I verified this by checking the local network IP through my mobile, as both devices were connected to the same Wi-Fi network. The InputManager is now capable of working with three types of input in one place - keyboard, touch directional pad, and swipe, all of them leading to a single nextDirection property, which is accessed by the main game loop.
I fixed up my previous issues with lives resetting to 3 for each level completed as well as start Game taking you back to level 1 rather than starting at the highest level you’ve unlocked. The ghost speed has been halved (from 2px to 1px/frame) which makes everything seem much more balanced with me running around at 60fps! I’ve added a proper pause menu overlay along with options to toggle Music & SFX - I had previously run into an issue where if you paused the game then played again the menu music would keep playing. To fix this I’m keeping track of all active WebAudio Oscillators and automatically stop them whenever we begin gameplay. We’ve added some really nice little touches too! For example, when you die Pac-Man will close his mouth, spin twice and slowly shrink away over 80 frames before disappearing completely. You’ll also get a sweet animation when you spawn growing up from 0 to full size over 40 frames. We originally couldn’t get the death animation working because we’d set our global variable gameActive = false during dying which turned off the entire update loop so I’ve updated Pac-Man’s update method to continue updating even when he’s dying / spawning. Finally, I made sure to make Pac-Man disappear once he dies to ensure no weird visuals happen after respawning. We added a yellow flash on finishing a level. Floating score popups show up every time you eat a ghost. Now there’s an animated HUD that shows your current score. Previously, canvas animations were off due to transform translation applied twice (once during animation and once more when drawing). Now we translate to our sprite’s center before applying any additional transformation.
Fixed all six power-up behaviours this session. Speed boost and double points were already working. The main rework was on shield, freeze, and slow. Shield now stays active until a ghost physically touches the player, when that happens, the ghost turns scared/blue instead of the player dying, and the shield remains active for future hits on a 15-second timer. Freeze keeps ghosts in their normal colour but completely stops their movement for 3 seconds - they’re still killable while frozen. Slow keeps ghosts at their normal appearance but skips movement every other frame, effectively halving their speed for 5 seconds. Also implemented proper ghost spawn behavior. Ghosts now spawn at the center of the maze (on or near the ghost house tiles) and release one by one first ghost after 2 seconds, then one every 3 seconds. While waiting to release they bob up and down inside the house. After death, the release sequence resets so ghosts trickle out again rather than all rushing at once. Pac-Man now spawns at a random open tile at least a third of the maze width away from the centre, so every life and every game starts from a different position. Maze connectivity fix was attempted this session but not completed - some maps still have corridors that can trap the player. Carrying this into the next session
IT’S DEVLOG TIMEE :»> It’s been a tough few days trying to figure out how to fix the MAZE, but I finally figured out how to do it through A* pathfinding. Fixed all the maps. Which took me so longggg. Also, Fixed speed inconsistency bugs and collision detection to eliminate Pac-Man getting stuck at maze tiles - movement now uses tile-based physics that checks every frame with no edge-case stalls, plus input buffering lets players queue moves ahead for responsive controls. Implemented proper ghost freeze behavior where frozen ghosts stop completely for 5 seconds, stay visible, and remain killable while frozen. Made the Extra Life now work on the screen when you get an Extra life it will update in the UI top middle and see a new Pac-man face get added. On the side of the Maps you can see there is no wall blocking, because now I made it a teleport to the other side.
It’s DEVLOG TIME:» Just pushed a much-needed update to the project! First up, I finally tracked down and killed a frustrating maze error in Level 10 that was completely breaking the game right near the finish line—so the final levels are officially working and playable now. While I was at it, I also took the time to write a proper README. It covers everything from setup instructions to gameplay mechanics, making the codebase a lot more welcoming and less of a black box for anyone who wants to test it out or contribute. Next up is getting some feedback and seeing how quickly people can break it! Also, when you are shielded for the power up, you can’t eat the ghosts.
Ships:
I made a Pac-man but with power ups and more ghosts as you proceed to level up. challenging part was making the maze I struggled a lot. I’m proud that I was able to complete such a project. When you get one of the power ups which is Shield your Pac-man becomes blue, so the ghosts can’t eat you and you can’t eat them. It isn’t a bug I made it that way....
|
1793008159.6180859
|
1793094559.6180859
|