|
19151
|
Untitled project by @PyGoober | Stardance
|
PyGoober
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled project by @PyGoober | Stardance
|
1793458066.6379101
|
1794062866.6379101
|
|
19152
|
My first slack bot! by @tyler090311 | Stardance
|
tyler090311
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @tyler090311 | Stard Title: My first slack bot! by @tyler090311 | Stardance...
|
1793537534.9743543
|
1794142334.9743543
|
|
19153
|
Ping Pong Project by @mati | Stardance
|
mati
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Ping Pong Project by @mati | Stardance
|
1793936858.7701273
|
1794541658.7701273
|
|
19154
|
Frictionless by @iamshashwatfr | Stardance
|
iamshashwatfr
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @iamshashwatfr | Stardance
|
1793897774.7565973
|
1794502574.7565973
|
|
19155
|
DungeonStacks by @ASOM | Stardance
|
ASOM
|
2
|
40.0
|
567
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-01T06:05:07Z", "hours": 15.0, "multiplier": 19.44, "payout": 298, "blessing": "neutral", "text": "In this ship, I have addressed commonly reported game issues and bugs. Additionally, I refactored the messiest parts of the codebase to improve to improve maintainability and introduced several UX enhancements. Resolved common community-reported issues and glitches Refactored core legacy sections for cleaner and more robust code Added dynamic screenshake effects Implemented popup numbers (combat/damage indicators) Added an in-game tutorial system More detailed info can be found in git log history", "repo": "https://github.com/ASOM846/DungeonStacks", "demo": "https://asom846.itch.io/dungeoncards"}, {"ship_num": 2, "ts": "2026-06-19T15:08:45Z", "hours": 25.0, "multiplier": 10.72, "payout": 269, "blessing": "neutral", "text": "I have created a card game inspired by Scoundrel. The most challenging part was managing a large amount of interactions between cards and making the game visually appealing.", "repo": "https://github.com/ASOM846/DungeonStacks", "demo": "https://asom846.itch.io/dungeoncards"}]...
|
[{"post_id": 19797, "ts": "202 [{"post_id": 19797, "ts": "2026-07-01T05:47:13Z", "hours": 0.6911, "text": "DungeonCards V0.1.10 Finishing touches before shipping Key features implemented in this version: Updated game version on itch.io Updated readme file Checkout Git log for additional info Cheers"}, {"post_id": 16946, "ts": "2026-06-27T14:50:33Z", "hours": 4.77, "text": "DungeonCards V0.1.9 UX update Key features implemented in this version: Architecture and game-play changes Implemented new TutorialState class and entry from main menu. Updated FloatingText now it’s starting size depends on the amount of damage dealt / hp healed Added ANVIL card, allowing player to repair weapon Added textures for new items Deleted unused includes Window is now resizable Added missing descriptions for items Changed buttons size in main menu Acknowledged and fixed bugs Wrong cards defeated counting in InteractionManager EnemyVsShield using wrong value when triggering FloatingText Blocked player from using items located in backpack, now player has to swap them with one item in hand Checkout Git log for additional info Cheers"}, {"post_id": 15711, "ts": "2026-06-25T15:45:38Z", "hours": 4.2694, "text": "DungeonCards V0.1.8 Key features implemented in this version: Architecture changes Simplified InteractionManager now instead of passing lots of arguments it passes new InteractionContext struct witch contains necessary variables. Game-play and graphic changes Key card can be used to open the chest Chest card can be open using Key contains huge amount of coins score Durability indicator for SPELL e.g. LIVESTEAL Added floating text it is used for displaying damage, healing etc. -Added swapping items between hands and backpack,. Be aware that when you want to for instance swap WEAPON_UPGRADE with WEAPON you need to select weapon first, other ways the weapon upgrade effect will apply itself to weapon. It is build like this to maintain simple compatibility with android build, that hopefully, will be out soon:D Checkout Git log for additional info Cheers"}, {"post_id": 14971, "ts": "2026-06-24T09:51:18Z", "hours": 5.5831, "text": "DungeonCards V0.1.7 Implemented features: Architecture changes: Cleaned card generation logic Implemented new CardGenerator class Added extra weapon textures Switched from random weapon generating to preset weapon configs Added weapon durability and durability indicator Added weapon max/min damage to make the game more random"}, {"post_id": 11958, "ts": "2026-06-19T14:49:54Z", "hours": 3.2069, "text": "DungeonCards V0.1.6 Finishing touches Implemented features: Implemented auto window resizing and auto item positioning Extracted piles aligning logic to new function Implemented current run progress bar Fully implemented Score and card description window in bottom left Implemented more weapon graphics and names Fixed ice wand graphic Implemented new Game Over / Game Won screen with return to menu button Implemented Flee button And much more e.g. bug fixes and little touches"}, {"post_id": 11873, "ts": "2026-06-19T10:40:48Z", "hours": 2.6083, "text": "DungeonCards V0.1.5 (old DungeonStacks) Menu and WindowManager Implemented features: Architecture changes: Extracted window initialization and handling to new WindowManager class New Menu class handled form WindowManager Graphics changes Custom font in menu (no plans on implementing in anywhere else) Game title drawing with shadow"}, {"post_id": 11393, "ts": "2026-06-18T17:29:36Z", "hours": 2.7969, "text": "DungeonCards V0.1.4 Graphics update Implemented features: Graphics changes: Background texture (thanks to NanoBanana) Vignette drawing Better card description rendering When card is hovered it pops up a bit making game more interactive and immersive Hands drawing itch.io Architecture changes: Better card interactions e.g. now attacking with weapon from backpack is impossible Empty piles e.g. left hand is now lighted up if selected item can be moved to it"}, {"post_id": 11223, "ts": "2026-06-18T11:27:00Z", "hours": 2.4167, "text": "DungeonCards 0.1.3 Implemented features: Graphics :D thanks to 0x72 assets from itch.io More spells Added missing resolving interactions TO-DO Implement remaining graphics Better UI Start menu High-score Checkout previous TO-DO"}, {"post_id": 11121, "ts": "2026-06-18T05:56:57Z", "hours": 4.3942, "text": "DungeonCardsV0.1.2 Implemented features: Added new item type SPELL Added new spells and graphics Added interactions for spells Added context aware highlighting Added hover card description drawing TO-DO Better graphics and UI Start Menu High-score"}, {"post_id": 10524, "ts": "2026-06-17T08:44:35Z", "hours": 2.7008, "text": "DungeonStack V0.1.1 Architecture changes: Shaped and improved core mechanic. Better randomness, now using weighted pool Implemented features: Added damage absorption item (shield)"}, {"post_id": 9919, "ts": "2026-06-16T13:02:25Z", "hours": 2.4494, "text": "DungeonStacks V0.1.0 First build to be called something playable. Working on improving core logic. Architecture changes: Extracted interactions to InteractionManager (split monolith logic into smaller methods) Added Element enum to Card struct to prevent “if-else” explosion Implemented features: Temporary drawings using Raylib shapes Added fire and ice wands Added fire and ice enemies Added cards counter under piles Fixed a bug where card elements were inherited by subsequent random spawns TO-DO / Next Steps: Handle victory/defeat conditions (Player HP <= 0) Resolve text clipping issues using text wrapping Replace temporary shapes with custom graphics"}, {"post_id": 9850, "ts": "2026-06-16T09:38:11Z", "hours": 3.4497, "text": "DungeonStacks working on core mechanics and essentials Implemented features: Text centering on cards Lose condition Architecture changes: Extracted game logic to separate classes e.g. Game class PileManager class Pile class Ui class Removed GameState class Need to be implemented: Better visuals start menu more types of items"}, {"post_id": 9263, "ts": "2026-06-15T15:35:52Z", "hours": 1.1214, "text": "DungeonStacks Core mechanics and essentials Currently features: Stack-Based Architecture Tactical combat system Dynamic UI and Centering Card eneration Interaction logic Upcoming features: Win/lose condition Visual feedback More interactions More card types"}]...
|
Title: DungeonStacks by @ASOM | Stardance
Devlogs Title: DungeonStacks by @ASOM | Stardance
Devlogs:
DungeonStacks Core mechanics and essentials Currently features: Stack-Based Architecture Tactical combat system Dynamic UI and Centering Card eneration Interaction logic Upcoming features: Win/lose condition Visual feedback More interactions More card types
DungeonStacks working on core mechanics and essentials Implemented features: Text centering on cards Lose condition Architecture changes: Extracted game logic to separate classes e.g. Game class PileManager class Pile class Ui class Removed GameState class Need to be implemented: Better visuals start menu more types of items
DungeonStacks V0.1.0 First build to be called something playable. Working on improving core logic. Architecture changes: Extracted interactions to InteractionManager (split monolith logic into smaller methods) Added Element enum to Card struct to prevent “if-else” explosion Implemented features: Temporary drawings using Raylib shapes Added fire and ice wands Added fire and ice enemies Added cards counter under piles Fixed a bug where card elements were inherited by subsequent random spawns TO-DO / Next Steps: Handle victory/defeat conditions (Player HP <= 0) Resolve text clipping issues using text wrapping Replace temporary shapes with custom graphics
DungeonStack V0.1.1 Architecture changes: Shaped and improved core mechanic. Better randomness, now using weighted pool Implemented features: Added damage absorption item (shield)
DungeonCardsV0.1.2 Implemented features: Added new item type SPELL Added new spells and graphics Added interactions for spells Added context aware highlighting Added hover card description drawing TO-DO Better graphics and UI Start Menu High-score
DungeonCards 0.1.3 Implemented features: Graphics :D thanks to 0x72 assets from itch.io More spells Added missing resolving interactions TO-DO Implement remaining graphics Better UI Start menu High-score Checkout previous TO-DO
DungeonCards V0.1.4 Graphics update Implemented features: Graphics changes: Background texture (thanks to NanoBanana) Vignette drawing Better card description rendering When card is hovered it pops up a bit making game more interactive and immersive Hands drawing itch.io Architecture changes: Better card interactions e.g. now attacking with weapon from backpack is impossible Empty piles e.g. left hand is now lighted up if selected item can be moved to it
DungeonCards V0.1.5 (old DungeonStacks) Menu and WindowManager Implemented features: Architecture changes: Extracted window initialization and handling to new WindowManager class New Menu class handled form WindowManager Graphics changes Custom font in menu (no plans on implementing in anywhere else) Game title drawing with shadow
DungeonCards V0.1.6 Finishing touches Implemented features: Implemented auto window resizing and auto item positioning Extracted piles aligning logic to new function Implemented current run progress bar Fully implemented Score and card description window in bottom left Implemented more weapon graphics and names Fixed ice wand graphic Implemented new Game Over / Game Won screen with return to menu button Implemented Flee button And much more e.g. bug fixes and little touches
DungeonCards V0.1.7 Implemented features: Architecture changes: Cleaned card generation logic Implemented new CardGenerator class Added extra weapon textures Switched from random weapon generating to preset weapon configs Added weapon durability and durability indicator Added weapon max/min damage to make the game more random
DungeonCards V0.1.8 Key features implemented in this version: Architecture changes Simplified InteractionManager now instead of passing lots of arguments it passes new InteractionContext struct witch contains necessary variables. Game-play and graphic changes Key card can be used to open the chest Chest card can be open using Key contains huge amount of coins score Durability indicator for SPELL e.g. LIVESTEAL Added floating text it is used for displaying damage, healing etc. -Added swapping items between hands and backpack,. Be aware that when you want to for instance swap WEAPON_UPGRADE with WEAPON you need to select weapon first, other ways the weapon upgrade effect will apply itself to weapon. It is build like this to maintain simple compatibility with android build, that hopefully, will be out soon:D Checkout Git log for additional info Cheers
DungeonCards V0.1.9 UX update Key features implemented in this version: Architecture and game-play changes Implemented new TutorialState class and entry from main menu. Updated FloatingText now it’s starting size depends on the amount of damage dealt / hp healed Added ANVIL card, allowing player to repair weapon Added textures for new items Deleted unused includes Window is now resizable Added missing descriptions for items Changed buttons size in main menu Acknowledged and fixed bugs Wrong cards defeated counting in InteractionManager EnemyVsShield using wrong value when triggering FloatingText Blocked player from using items located in backpack, now player has to swap them with one item in hand Checkout Git log for additional info Cheers
DungeonCards V0.1.10 Finishing touches before shipping Key features implemented in this version: Updated game version on itch.io Updated readme file Checkout Git log for additional info Cheers
Ships:
I have created a card game inspired by Scoundrel. The most challenging part was managing a large amount of interactions between cards and making the game visually appealing.
In this ship, I have addressed commonly reported game issues and bugs. Additionally, I refactored the messiest parts of the codebase to improve to improve maintainability and introduced several UX enhancements. Resolved common community-reported issues and glitches Refactored core legacy sections for cleaner and more robust code Added dynamic screenshake effects Implemented popup numbers (combat/damage indicators) Added an in-game tutorial system More detailed info can be found in git log history...
|
1793955393.5837157
|
1794041793.5837157
|
|
19156
|
HackPad by @Hongyu | Stardance
|
Hongyu
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: HackPad by @Hongyu | Stardance
|
1793379151.2252734
|
1793983951.2252734
|
|
19157
|
My awesome macropad! by @hasininam49 | Stardance
|
hasininam49
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @hasininam49 | Star Title: My awesome macropad! by @hasininam49 | Stardance...
|
1793497921.4350595
|
1794102721.4350595
|
|
19158
|
My awesome macropad! by @Ritika | Stardance
|
Ritika
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @Ritika | Stardance
|
1793530337.1694393
|
1794135137.1694393
|
|
19159
|
N-body simulator by @bd6015958 | Stardance
|
bd6015958
|
1
|
0.0
|
1
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-16T10:03:55Z", "hours": 0.0, "multiplier": 2.45, "payout": 1, "blessing": "neutral", "text": "This is a n-body simulator. I built this becuase I am interested in astrophysics.", "repo": "https://github.com/lmq-v/Orbital-Dynamics", "demo": "https://orbital-dynamics-ujpw.vercel.app/"}]...
|
[{"post_id": 9859, "ts": "2026 [{"post_id": 9859, "ts": "2026-06-16T09:58:28Z", "hours": 0.4133, "text": "physics engine"}]...
|
Title: N-body simulator by @bd6015958 | Stardance
Title: N-body simulator by @bd6015958 | Stardance
Devlogs:
physics engine
Ships:
This is a n-body simulator. I built this becuase I am interested in astrophysics....
|
1794002072.9083405
|
1794088472.9083405
|
|
19160
|
first hit wonder by @AriNag | Stardance
|
AriNag
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: first hit wonder by @AriNag | Stardance
|
1793803856.5643303
|
1794408656.5643303
|
|
19161
|
E-Ink Music Player by @udayakula2011 | Stardance
|
udayakula2011
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: E-Ink Music Player by @udayakula2011 | Star Title: E-Ink Music Player by @udayakula2011 | Stardance...
|
1793375310.1582377
|
1793980110.1582377
|
|
19162
|
EpicOS by @Epicninja3 | Stardance
|
Epicninja3
|
2
|
13.0
|
1
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-13T16:30:48Z", "hours": 0.0, "multiplier": 2.93, "payout": 1, "blessing": "neutral", "text": "EpicOS is a web-based OS with several helpful features! EpicOS has a notebook app where you can save up to 2 note documents. It also has a solar system app where you can view the live position of the planets in our solar system. Additionally, EpicOS has a calculator app with several important conversions, and a racing game where you can try to set your best lap time! EpicOS also features a new weather app, simply type in your city to view the weather! The weather app includes important information such as the high, low, wind speed, wind direction, sunset/sunrise timings, precipitation data, and a 7-day forecast! EpicOS also allows you to customize your wallpaper. EpicOS also includes an embedded chatbot powered by Thinkstack which is trained to answer any of your questions about EpicOS!", "repo": "https://github.com/epicninja3/EpicOS", "demo": "https://epicninja3.github.io/EpicOS"}, {"ship_num": 2, "ts": "2026-06-28T20:23:43Z", "hours": 13.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "EpicOS is an interactive webOS where you can write notes, explore our solar system, use a calculator, and play a little racing game! EpicOS is a fun and helpful OS for your needs. It has a live clock, a live view of the planets in our solar system, and other useful apps.", "repo": "https://github.com/epicninja3/EpicOS", "demo": "https://epicninja3.github.io/EpicOS"}]...
|
[{"post_id": 24725, "ts": "202 [{"post_id": 24725, "ts": "2026-07-08T14:23:58Z", "hours": 0.4097, "text": "I kind of forgot to log some of my time, but I added a few more features to EpicOS! New Weather App!! Simply type in the city you want, and the app will show the current temperature, time, wind speed/direction, sunrise/sunset timings, precipitation data, as well as a 7-day forecast. Refreshed note launcher, which can have up to 2 saves (I will probably increase this or make it unlimited later). The calculator has more conversions, such as Lb-Kg, In-Cm, and others. New Settings app that allows you to customize your wallpaper. Currently has 3 different options. I also did some other minor fixes in the game and throughout the project."}, {"post_id": 17880, "ts": "2026-06-28T20:19:26Z", "hours": 1.7817, "text": "Added a calculator that has conversions as well. Currently, it can convert from Miles to Kilometers and Fahrenheit to Celsius (and vice versa). I also added a simple racing game to the OS where you can set a lap time!"}, {"post_id": 14430, "ts": "2026-06-23T15:42:30Z", "hours": 3.6553, "text": "I added a notes app! The notes app has a launcher that currently allows you to perform three functions. You can create a new document, save that document, and then load the most recent save. I also added all the planets in my live solar system diagram, and locked the zoom so you don’t zoom out too much and lose the solar system."}, {"post_id": 10130, "ts": "2026-06-16T18:53:43Z", "hours": 3.6453, "text": "I worked on making my OS look a bit better and added an application that shows you the live position of planets in our solar system. It took me a while to find some sort of API that will give the data for it, but I managed to get the inner planets for now!"}, {"post_id": 9603, "ts": "2026-06-16T00:14:57Z", "hours": 3.5022, "text": "Worked on the Welcome page. I also added a topbar. Additionally, the window can close and later opened by clicking on “Welcome!”."}]...
|
Title: EpicOS by @Epicninja3 | Stardance
Devlogs: Title: EpicOS by @Epicninja3 | Stardance
Devlogs:
Worked on the Welcome page. I also added a topbar. Additionally, the window can close and later opened by clicking on “Welcome!”.
I worked on making my OS look a bit better and added an application that shows you the live position of planets in our solar system. It took me a while to find some sort of API that will give the data for it, but I managed to get the inner planets for now!
I added a notes app! The notes app has a launcher that currently allows you to perform three functions. You can create a new document, save that document, and then load the most recent save. I also added all the planets in my live solar system diagram, and locked the zoom so you don’t zoom out too much and lose the solar system.
Added a calculator that has conversions as well. Currently, it can convert from Miles to Kilometers and Fahrenheit to Celsius (and vice versa). I also added a simple racing game to the OS where you can set a lap time!
I kind of forgot to log some of my time, but I added a few more features to EpicOS! New Weather App!! Simply type in the city you want, and the app will show the current temperature, time, wind speed/direction, sunrise/sunset timings, precipitation data, as well as a 7-day forecast. Refreshed note launcher, which can have up to 2 saves (I will probably increase this or make it unlimited later). The calculator has more conversions, such as Lb-Kg, In-Cm, and others. New Settings app that allows you to customize your wallpaper. Currently has 3 different options. I also did some other minor fixes in the game and throughout the project.
Ships:
EpicOS is an interactive webOS where you can write notes, explore our solar system, use a calculator, and play a little racing game! EpicOS is a fun and helpful OS for your needs. It has a live clock, a live view of the planets in our solar system, and other useful apps.
EpicOS is a web-based OS with several helpful features! EpicOS has a notebook app where you can save up to 2 note documents. It also has a solar system app where you can view the live position of the planets in our solar system. Additionally, EpicOS has a calculator app with several important conversions, and a racing game where you can try to set your best lap time! EpicOS also features a new weather app, simply type in your city to view the weather! The weather app includes important information such as the high, low, wind speed, wind direction, sunset/sunrise timings, precipitation data, and a 7-day forecast! EpicOS also allows you to customize your wallpaper. EpicOS also includes an embedded chatbot powered by Thinkstack which is trained to answer any of your questions about EpicOS!...
|
1793861373.572419
|
1793947773.572419
|
|
19163
|
A generational macropad! by @petiteUnicone | Stard A generational macropad! by @petiteUnicone | Stardance...
|
petiteUnicone
|
0
|
0.72
|
0
|
[]
|
[{"post_id": 9981, "ts": "2026 [{"post_id": 9981, "ts": "2026-06-16T14:53:42Z", "hours": 0.7222, "text": "So I decided to follow the guides and make a HACKPAD!!! So far I have got the PCB done… but right now it is a copy of the guide. It is a journey because of my clumsy inability to read the images properly! The steps were easy when I understood where I went wrong…. Well after downloading everything at the start I wondered how I would record the time spent and then on slack I saw that we should use lapse! Total lifesaver! My image is simple but I love how its going as this is my first ever hardware project!"}]...
|
Title: A generational macropad! by @petiteUnicone Title: A generational macropad! by @petiteUnicone | Stardance
Devlogs:
So I decided to follow the guides and make a HACKPAD!!! So far I have got the PCB done… but right now it is a copy of the guide. It is a journey because of my clumsy inability to read the images properly! The steps were easy when I understood where I went wrong…. Well after downloading everything at the start I wondered how I would record the time spent and then on slack I saw that we should use lapse! Total lifesaver! My image is simple but I love how its going as this is my first ever hardware project!...
|
1793497836.0028617
|
1794102636.0028617
|
|
19164
|
BadGPT by @28taidan | Stardance
|
28taidan
|
1
|
121.0
|
1974
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T22:47:09Z", "hours": 121.0, "multiplier": 16.85, "payout": 1974, "blessing": "neutral", "text": "badGPT is a conglomeration of sequential ML projects I did this summer, culminating in a chatbot like ChatGPT or Claude built from scratch using just python and numpy. I started off by building a name generation model, then a Shakespeare writing model, then finally a chatGPT-esque model. The model produces, for the most part, complete gibberish, so this was less a practical project and more an exercise in understanding how everything works. It performs so poorly because it’s so small. Models need a lot of parameters to be able to capture all the nuances required to produce coherent text, which makes the models much slower to train. The final model I made includes around 120,000 parameters, 4 transformer blocks of 4 attention heads each, and 64 tokens of context. It’s based largely on GPT-2, which for reference had about 1.5 billion parameters. Current frontier models, like Anthropic’s fable, have trillions of parameters and can have millions of input tokens, so it makes sense that my model is too small to make much sense at all. Even at its small size, it took my laptop more than 20 hours to train, so scaling up with my current hardware is not feasible. Many people like using libraries like pytorch and tensorflow, which include classes that handle backpropagation (the system that’s at the heart of letting the models learn), but I wanted to start from scratch so I wrote my own. If you wish to try any of my models out, you can visit the demo website (click try project), and click through the tabs to see each of the models. It all runs in your browser. You can also look through the Jupyter notebooks in the Github repository to get a sense of how everything works.", "repo": "https://github.com/Luchik28/BadGPT", "demo": "https://luchik28.github.io/BadGPT/"}]...
|
[{"post_id": 63888, "ts": "202 [{"post_id": 63888, "ts": "2026-09-07T22:03:29Z", "hours": 0.3219, "text": "Fixed up the readme a bit in preparation to ship. Specifically, I added info on what all the files do, but I named them poorly and then forgot what most of them do so it’s kind of confusing."}, {"post_id": 63871, "ts": "2026-09-07T21:24:10Z", "hours": 3.705, "text": "Trained the model a little more, exported it, wrote some UI to make it look more like a chatbot. It still sounds like gibberish. Sometimes I imagine that it’s output changes slightly depending on the context (for example, more numbers if I ask it a number related question, and a list if I ask it for a list, etc), but I’m probably just imagining it, it’s really just gibberish. Still kinda cool tho. You can check out the demo at https://luchik28.github.io/BadGPT/ ."}, {"post_id": 63606, "ts": "2026-09-07T15:13:11Z", "hours": 10.0569, "text": "Added an EOS ID, which is a special token that the model can output to indicate that it’s done. I built a script to insert this in between passages in the training data, so it can learn when it should shut up (otherwise it will yap forever, until it hits the max number of output tokens). This meant I had to retrain the entire model, but got it down to a loss of around 3.46. Obviously, it’s not very good. But I’m pretty sure the only way to improve is to scale up the model size and training time, something I don’t really have the capacity to do (this model trained for 15 hours on my laptop). I will probably continue by adding this model to my demo website, and build a chatGPT like UI, just for fun. After that, I think it might be time to ship!"}, {"post_id": 63248, "ts": "2026-09-06T23:29:21Z", "hours": 8.4769, "text": "Switched to using the fineweb edu dataset, instead of shakespear. This is the dataset I will use to train my actual model on. It’s a highly currated database of the internet, and is similar to what GPT2 was trained on (although the actual db they trained it on is closed source). I also reformated the sampling system so you can put in a query and get a response, as long as the query takes up less tokens than the context. Other than swapping out the training file, it’s the exact same. Next, I will probably implement a special ending token to my tokenizer, and also increase the scale of my model a little bit. I can’t increase it all the way to what Karpathy does in his tutorial (he uses cloud computing, so he paid to rent out like 8 64GB GPUs, or something like that), since I don’t want to spend money training it. However I think I can squeeze a little more out of my laptop."}, {"post_id": 49298, "ts": "2026-08-18T01:13:10Z", "hours": 9.3886, "text": "Started working on a more advanced tokenizer. The tokenizer is what splits the input text from words into numbers, and back again. Before, I was using a 10 dimensional embedding, where each letter is represented by a 10 long array (each value representing a dimension). But current models have much more advanced tokenizers, which often encompass entire words, or parts of words for longer words. This works using Byte Pair Encoding, which turns all of the letters pairs of letters into their utf encodings (usually 8), then iteratively merging the most common consecutive pairs into tokens to add to the vocabulary. You can see how tokenizers work at https://tiktokenizer.vercel.app/ , which is a cool website that lets you play around with stuff like that."}, {"post_id": 42029, "ts": "2026-08-06T16:03:32Z", "hours": 1.1833, "text": "Updated the demo website to include the wavenet model, and the new self-attention shakespear model. You can check it out here ."}, {"post_id": 41371, "ts": "2026-08-05T15:22:03Z", "hours": 1.2797, "text": "I finished training it! It finished with a val loss of around 1.76, it got down to 1.73 but ticked up at the end. The output is pretty good, but not substantially better than the wavenet model. However, it’s vaguely word-like, and took 20 hours to train so I’m not sure how much larger I can make the model before my laptop implodes. Next I will probably try to find a question-answer training dataset, so that I can start training it to answer questions. This step that I’ve been working on is the pre-training step, where I teach the model to basically spit out documents. Next, I have to have it spit out documents that happen to be question-answer documents."}, {"post_id": 41078, "ts": "2026-08-05T01:14:23Z", "hours": 9.7053, "text": "I made a bunch of tiny improvements. I didn’t change the architecture at all, but I did change the optimizer to AdamW. The optimizer is what controls how much each parameter is changed each epoch. Before, I was using a set learning rate, of about .1 for the first 80% of training then decreasing to .01 for the last 20%. Decreasing it at the end is important because as the loss settles into a local minimum, it might not be able to go to the lowest point because it keeps overshooting it since the lr is too high. Conversely, we can’t keep the lr too small the whole time because it might settle into a very tiny local minima that it might have been able to go over with a higher learning rate. It would also take forever. AdamW helps improve the optimizing step by changing the learning rate per parameter, helping the model train as fast as possible without overfitting. Overfitting isn’t really an issue I’m worrying about since my model is pretty small (around 56k params), so it’s not really large enough to learn the ins and outs of my dataset. Anyway I also changed the logging step, so it now logs validation dataset loss in addition to the training dataset loss. I split the dataset into train and validation so I can make sure it’s not overfitting. Currently the val loss is at 1.76, which is a lot better than where we were at before, which makes me hopeful. Training has around another 7,000 epochs to go, but Stardance is yelling at me I should write another devlog now so here you go, Stardance. I’m looking forward to sampling the model and seeing how much it’s improved!"}, {"post_id": 38899, "ts": "2026-08-01T14:11:19Z", "hours": 8.9297, "text": "I implemented self attention! I will try to explain here, but will do a terrible job: basically, what that is, is it lets the model decide what tokens in the input are more important than the others. The first thing I did was scrap the wavenet model, and switched to a simple bigram model. The second thing I implemented was bag of words, which edits the input tokens so every element is the average of that element and all that came before it. This lets all of the tokens “talk” to eachother. This is all fine and dandy but since all the things are averaged then you don’t know where things came from, and positional data is lost, so we lose a lot of resolution and data, so that sucks. So we have to encode positional data. So instead of just averaging all the elements that came before, we expand each averaged element into a list, which has all the elements in a row instead of averaging them into one number. So the first row could be [1, 0, 0] and the second [1, 2, 0] and the third [1, 2, 3], etc. We do this by masking it with the tril function, from numpy (very cool). But this is problematic, because all of the elements are given the exact same weight. A letter 34 characters back gets the same weight as the last character in the input (which is the letter immediately preceding the predicted letter, the output). To fix this, we add self attention! This is modeled after the groundbreaking paper Attention is All You Need, which started the whole AI hype thing. How it works is each token has a linear layer (that multiplies it by learned weights) called the key, and another called the query. The query is kind of like what that token is looking for, and the key is kind of like what that token has. And these can be multiplied with the keys and queries of all the other tokens, and that lets you know which token has the stuff that the most other tokens are looking for, and is thus more important and can be given more weight. That is a single head of attention, there are multiple heads that can specialize in different things. This, in theory, should increase performance. But it also drastically increases the amount of time it takes to train. The model only has ~56k parameters, which is less than half of the wavenet model, but takes a lot more time to do it’s thing. This is the output from the results of more than 13 hours of training. As you can see from the loss function, the loss was decreasing at a steady rate, so more training could probably improve it. Plus, this was at a highish learning rate the whole time (.1) so decreasing it would probably further improve it. But I can’t do anything on my computer while this is training or it runs out of RAM, and I have to use my computer now, so I will be moving on for now."}, {"post_id": 34926, "ts": "2026-07-26T01:22:29Z", "hours": 6.5472, "text": "I increased the block size from 8 characters to 64. This means that instead of the model taking in the previous 8 characters and outputting the next one, it takes in the previous 64 characters and outputs the next. This means that it should be able to keep track of longer words so it doesn’t get lost in them. However, it doesn’t seem to be improving the model too much, although that might be because I haven’t trained it as much as the others. I’ve done roughly 200,000 epochs, which took a long time, since this model is much larger (110,415 parameters vs 45,000), and has 6 hidden layers as apposed to 2, which means it is a lot slower. As you can see in the loss graph, it probably could make further gains, although it seems to be mostly good."}, {"post_id": 33555, "ts": "2026-07-23T16:18:09Z", "hours": 1.5631, "text": "Trained the wavenet architecture on a file with just shakespear in it. It’s got the structure down well, and sometimes can do words and wordlike outputs, but generally spouts straight gibberish. I will try to follow a lecture to build a better Tokenizer and Transformer next time. Right now each character is treated as a token, and embedded into 10 dimensions, it would be better if pairs of characters were treated as tokens and embedded. Increasing the context size could also help, it’s currently an input of the previous 8 characters and outputting 1. This is it’s output:"}, {"post_id": 32988, "ts": "2026-07-22T14:44:00Z", "hours": 8.5858, "text": "Implemented the wavenet architecture. Usually, during the flattening phase, the tensor goes from the shape (batch num, block size, embedding dimensions) to (batch num, block size * embedding dimensions). This squishes all of the embedded characters into one dimension. Wavenet does that more gradually, it slowly merges the different letters. So the first two letter embeddings get squished into one, then the next two, etc, and in the next layer then you have the first 4, then the next four, until by the final layer you have just one group of all the letters, which is the same as the original method, just a much more gradual approach. The first image is the training loss, the huge cliff is when the learning rate decreased. The second image is a visualization of the wavenet architecture from the paper. You can see that in each layer, nearby groups of input get merged together. In the original method, the graph would look like all of the inputs going to the 1st dot in the hidden layer, then continuing up. Next I will be actually building a GPT instead of this names project."}, {"post_id": 32125, "ts": "2026-07-21T02:19:34Z", "hours": 6.8089, "text": "I did a bunch of things to prep for implementing a wavenet architecture, which basically changes the model so instead of taking in all the characters of input at once and squishing them all into the first layer, it gradually puts them in at each separate layer. First, I put more stuff in classes! This didn’t really change the functionality, but instead of embedding the characters and flattening the model in separate chunks, I put them in their own classes so they can get put in the list of layers, and we can just run the input through each layer in the list, and compare it with the target at the end, instead of having half the layers in the list and half as separate chunks, which is a lot smoother. So the entire model is just: model = Sequential ([ Embedding ( vocab_size , n_embd ), FlattenConsecutive ( 2 ), Linear ( n_embd * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), FlattenConsecutive ( 2 ), Linear ( n_hidden * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), FlattenConsecutive ( 2 ), Linear ( n_hidden * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), Linear ( n_hidden , vocab_size ), ]) Which I think is really cool. I also improved the loss graph, previously it looked like the screenshot on the right, because each iteration’s loss is graphed. Because our batch size is 32, which means in each iteration we look at just 32 inputs/output, a good deal of what the loss will be depends on how lucky we are with the input/output. Over a great number of iterations, it averages out into the correct value, though, so to fix the graph, we instead plot the average of every 1000 iterations, which lets us see a lot more detail that otherwise would be lost in the noise (the two loss graphs I added are not of the same model, but you get the idea). Anyway now I’m going to actually implement the wavenet architecture!"}, {"post_id": 29913, "ts": "2026-07-17T02:41:08Z", "hours": 3.23, "text": "I followed Karpathy’s lecture on backpropagation, where he implemented backpropagation manually. In the series, he’s using Pytorch, which does it for you, which is why he’s doing it manually. I’m not using Pytorch, so the only way to do it is to do it manually, so I didn’t get to add too much to the code, I just verified that I had implemented it correctly and learned a bunch. It is still pretty confusing though, and I couldn’t solve any of the exercises in the lecture without watching his explanations. Anyway here’s a name it generated that I think is pretty cool."}, {"post_id": 29276, "ts": "2026-07-16T02:51:51Z", "hours": 0.7719, "text": "Added a demo page! You can check it out here: https://luchik28.github.io/BadGPT/ . I saved the model weights, built a script that reconstructs the model using those weights, and hosted it using github pages."}, {"post_id": 29257, "ts": "2026-07-16T01:45:50Z", "hours": 3.1169, "text": "Put my model into the Layer class, so I can easily create lots of layers. The graph shows the activation distribution by layer. Each layer is pretty similar, as you can see. This devlog marks the end of the fourth lecture in Andrej Karpathy’s makemore series, out of 7, so we’re getting there! That’s just under 8 hours or lecture watched (so I spend roughly 5 minutes coding for every minute of lecture watched). Pretty interesting."}, {"post_id": 25900, "ts": "2026-07-10T12:09:18Z", "hours": 13.8508, "text": "I was playing around with how changing the number of epochs/other variable affected the output, and seeing how that differed to before I implemented Batch normalization, and so tried to put the epochs up a lot. I ended up training it for 20,000,000 epochs, which took like 8 hours, which is why this devlog has so much time logged. It didn’t really improve it much, you can see by the loss graph it didn’t go down very much at all, so I’ll need to change something in how the code works. It was still fun though."}, {"post_id": 24311, "ts": "2026-07-07T20:05:56Z", "hours": 2.4747, "text": "I worked on switching to a Jupyter notebook instead of just a python file, this made it easier since I didn’t have to constantly retrain the model, and also could print out stuff in line. I also added batch normalization, which helps change the range (really the standard deviation) of the values before going into the activation function (tanh) so that the values are more spread out. tanh squishes all values between -1 and 1, so if all of the numbers are greater than 1 or less than -1, then all of the values will essentially be squished to either -1 or 1, which makes the model lose a lot of the data. But if you divide all the numbers so that they are all closer to 0, then the activation function is a lot more spread out and the data is preserved. (I got the photo from google, I think it’s helpful when visualizing it)."}, {"post_id": 20360, "ts": "2026-07-01T22:48:01Z", "hours": 1.0503, "text": "I made a bunch of little improvements, including increasing the character encodings to 10 dimensions up from 2, increasing the epochs to 200,000, and also decreasing the learning rate from .1 to .01 for the laster 50,000 epochs. Although the loss is significantly lower than Andrej Karpathy’s makemore (which I modeled my model after), it’s names are worse. Karpathy got 2.17 ish on the testing dataset, while I got 1.776. However, Karpathy’s generated slightly abnormal but reasonably word-like names, like “jeron” and “ham” while mine where a little more random (“xxxhorlis” is one of them). I’m not sure how to improve from here, I don’t think increasing the epochs will do much, it already took around 10 minutes to train this model, I think we’ll get diminishing returns. I will, as always, continue on to the next video in Karpathy’s series, hoping that his tips will help improve it."}, {"post_id": 17855, "ts": "2026-06-28T19:57:08Z", "hours": 2.8889, "text": "I tuned the learning rate (The magnitude of how much it changes the weights, which is multiplied by the gradient of each weight to get the final change), added better printouts when training (Added a neat progress bar/tracking, output the loss, and a timer), and also using plotmatlib to plot the embeddings. The graph is how the model arranged each letter in space. What’s interesting is similar letters (like the ending character “.” and “e”, which both are commonly found near the end of the word) are in similar spots, so the model has sorted out some sort of meaning from their placements, which I think is pretty cool. The names are still quite nonsensicle, I think I might have to enlarge the model a little bit to improve performance, which means waiting longer for it to train :("}, {"post_id": 15817, "ts": "2026-06-25T18:20:16Z", "hours": 5.8631, "text": "I improved my model based off of Kerpathy’s makeMore part two tutorial and a 2003 paper by bengio et al (link is https://jmlr.org/papers/volume3/tmp/bengio03a.pdf ), it was really interesting. I increased the input size, so it takes in the previous 3 letters as an input instead of 1, and encoded each letter in a two dimensions instead of one hot encoding. I also had to start using numPy due to needing to do efficient matrix multiplication (numPy does it in C in a heavily optimized fashion, I considered trying to do this but decided it was out of the scope of the project). Doing it in just python would be way too slow. I also optimized it a little bit, having it select 32 examples randomly from the data set for each epoch, instead of just using the whole thing, which made it a lot faster while still training over the whole set. Hopefully this will make it produce more accurate results!"}, {"post_id": 12206, "ts": "2026-06-19T22:30:34Z", "hours": 1.1233, "text": "I finally got it to generate some names! They are sampled below. I watched the first half of Andrej Karpathy’s makemore video, and built a 2D array of the number of each instance of a letter following another instance. Then, when generating the name, it takes an array of the number of times in the training set each letter followed the previous letter in the name, multiplies that number by a random number 0 to 1, and chooses the highest number as the next letter in the name. This doesn’t work too well, as shown below, so I will spend some time improving, but it’s a start! Some names it generated are sampled below."}, {"post_id": 11053, "ts": "2026-06-18T02:41:06Z", "hours": 5.3719, "text": "Having completed the MLP I described in my last devlog, I set out to try to follow the next tutorial in the list I found. However, after I listened to the description of it, which is basically just a model that can take in a database of words and produce more words that sound similar, I foolishly believed I could try to build something similar without following the tutorial. I did take the database of names from the tutorial, since I will need those to train the model. I started by transforming the inputs (the previous letter in the word) into numbers, and then the output (a number) back into a letter. My first attempt just put in the ASCII code for the letter, and the rounded down output number. The first issue was I used the entire database to train, which took forever and quickly hit the maximum recursion depth, so I switched to using only the first 500 examples (using the entire database, combined with super high differences between the output and the expected output resulted in the initial loss being 1,934,198,245, compared to a loss of like 4 when just testing my MLP). After that, I got it to actually finish training without crashing, however, the loss didn’t go down, and it always outputted a null character. I realized I had been really stupid, as the tanh function at the end of every neuron in the MLP shrinks the result between -1 and 1, so the result could only ever be the ASCII codes 0 or 1, which are null. So instead, I changed it so instead of outputting the ASCII code directly, it outputs a 27 long array, each index representing a letter (and the last representing end of name), each value at an index represents the probability of that letter being chosen, so to decode the results it just has to find the highest probability, check that it’s not the last element, and add 97 to it’s index to get the ASCII codes (because the letter “a” is at 97, so if it’s index 0 and meant to be “a” it has to adjust). This led it to actually output letters, but it always outputted the same letter, as shown in the screenshot. The loss dropped rapidly and then plateaued at around 2000. I found some bugs (gradient accumilating over time instead of resetting each epoch) and made some changes (instead of inputting an ASCII code, it inputs in the same format as the output), but nothing had any effect. After thinking, I realized that the model is just picking the most common letter, and always outputting it. That’s why the loss can’t get any lower than 2000, because that’s the limit of how good this strategy can get. However, I have no idea how to fix this issue, and somehow teach the model the meaning behind the letters, so I will accept defeat and watch the tutorial, then implement what I learned."}, {"post_id": 9520, "ts": "2026-06-15T21:49:01Z", "hours": 4.8256, "text": "I implemented an MLP, I watched the entire Micrograd explanation by Andrej Karpathy, which was really interesting. I followed along, and played around with tuning my model (that does absolutely nothing useful) to predict stuff better. It has Value objects, which store the data, as well as gradients, and the operation/previous numbers used to create them, as well as all the operations. This can be used to calculate the gradient (or how much each Value object affected the last Value in the chain of operations), which is basically all you need for backpropogation (which is where it goes back and calculates how much each weight/bias affects the final output). It also has classes for each neuron, which is a collection of Values that act as the inputs, the weights (which are randomly generated at the start), and the bias for that nueron. These neurons make up layers, and the layers make up the MLP (multilayer perceptron). I created a couple arrays of inputs, and the desired output, which has the output for each input array. To train it, you have the model predict something, then calculate the loss (or the sum of how far away each prediction was squared), then do the backpropogation (go through each parameter, or each weight and bias), find out how much and in what direction it affected the loss function, and finally change each parameter slightly so it moves the loss in the right direction. As you can see in the screenshot, I got it down pretty low. This will be useful because when I am training my LLM, I will need to use a neural network like this, and get the loss down as low as possible so it predicts better words and produces better results. Karpathy’s video is at https://www.youtube.com/watch?v=VMj-3S1tku0&list=PLAqhIrjkxbuWI23v9cThsA9GvCAUhRvKZ&index=2 , it’s really quite amazing, I learned so much from it, and I haven’t even learned Calculus yet, which he states is a prerequisite in the description, I highly recommend if you’re interested. Next I will need to work on implementing transformers (which takes in the input (words), and derives meaning from them by encoding them into a vector)."}]...
|
Title: BadGPT by @28taidan | Stardance
Devlogs:
I Title: BadGPT by @28taidan | Stardance
Devlogs:
I implemented an MLP, I watched the entire Micrograd explanation by Andrej Karpathy, which was really interesting. I followed along, and played around with tuning my model (that does absolutely nothing useful) to predict stuff better. It has Value objects, which store the data, as well as gradients, and the operation/previous numbers used to create them, as well as all the operations. This can be used to calculate the gradient (or how much each Value object affected the last Value in the chain of operations), which is basically all you need for backpropogation (which is where it goes back and calculates how much each weight/bias affects the final output). It also has classes for each neuron, which is a collection of Values that act as the inputs, the weights (which are randomly generated at the start), and the bias for that nueron. These neurons make up layers, and the layers make up the MLP (multilayer perceptron). I created a couple arrays of inputs, and the desired output, which has the output for each input array. To train it, you have the model predict something, then calculate the loss (or the sum of how far away each prediction was squared), then do the backpropogation (go through each parameter, or each weight and bias), find out how much and in what direction it affected the loss function, and finally change each parameter slightly so it moves the loss in the right direction. As you can see in the screenshot, I got it down pretty low. This will be useful because when I am training my LLM, I will need to use a neural network like this, and get the loss down as low as possible so it predicts better words and produces better results. Karpathy’s video is at https://www.youtube.com/watch?v=VMj-3S1tku0&list=PLAqhIrjkxbuWI23v9cThsA9GvCAUhRvKZ&index=2 , it’s really quite amazing, I learned so much from it, and I haven’t even learned Calculus yet, which he states is a prerequisite in the description, I highly recommend if you’re interested. Next I will need to work on implementing transformers (which takes in the input (words), and derives meaning from them by encoding them into a vector).
Having completed the MLP I described in my last devlog, I set out to try to follow the next tutorial in the list I found. However, after I listened to the description of it, which is basically just a model that can take in a database of words and produce more words that sound similar, I foolishly believed I could try to build something similar without following the tutorial. I did take the database of names from the tutorial, since I will need those to train the model. I started by transforming the inputs (the previous letter in the word) into numbers, and then the output (a number) back into a letter. My first attempt just put in the ASCII code for the letter, and the rounded down output number. The first issue was I used the entire database to train, which took forever and quickly hit the maximum recursion depth, so I switched to using only the first 500 examples (using the entire database, combined with super high differences between the output and the expected output resulted in the initial loss being 1,934,198,245, compared to a loss of like 4 when just testing my MLP). After that, I got it to actually finish training without crashing, however, the loss didn’t go down, and it always outputted a null character. I realized I had been really stupid, as the tanh function at the end of every neuron in the MLP shrinks the result between -1 and 1, so the result could only ever be the ASCII codes 0 or 1, which are null. So instead, I changed it so instead of outputting the ASCII code directly, it outputs a 27 long array, each index representing a letter (and the last representing end of name), each value at an index represents the probability of that letter being chosen, so to decode the results it just has to find the highest probability, check that it’s not the last element, and add 97 to it’s index to get the ASCII codes (because the letter “a” is at 97, so if it’s index 0 and meant to be “a” it has to adjust). This led it to actually output letters, but it always outputted the same letter, as shown in the screenshot. The loss dropped rapidly and then plateaued at around 2000. I found some bugs (gradient accumilating over time instead of resetting each epoch) and made some changes (instead of inputting an ASCII code, it inputs in the same format as the output), but nothing had any effect. After thinking, I realized that the model is just picking the most common letter, and always outputting it. That’s why the loss can’t get any lower than 2000, because that’s the limit of how good this strategy can get. However, I have no idea how to fix this issue, and somehow teach the model the meaning behind the letters, so I will accept defeat and watch the tutorial, then implement what I learned.
I finally got it to generate some names! They are sampled below. I watched the first half of Andrej Karpathy’s makemore video, and built a 2D array of the number of each instance of a letter following another instance. Then, when generating the name, it takes an array of the number of times in the training set each letter followed the previous letter in the name, multiplies that number by a random number 0 to 1, and chooses the highest number as the next letter in the name. This doesn’t work too well, as shown below, so I will spend some time improving, but it’s a start! Some names it generated are sampled below.
I improved my model based off of Kerpathy’s makeMore part two tutorial and a 2003 paper by bengio et al (link is https://jmlr.org/papers/volume3/tmp/bengio03a.pdf ), it was really interesting. I increased the input size, so it takes in the previous 3 letters as an input instead of 1, and encoded each letter in a two dimensions instead of one hot encoding. I also had to start using numPy due to needing to do efficient matrix multiplication (numPy does it in C in a heavily optimized fashion, I considered trying to do this but decided it was out of the scope of the project). Doing it in just python would be way too slow. I also optimized it a little bit, having it select 32 examples randomly from the data set for each epoch, instead of just using the whole thing, which made it a lot faster while still training over the whole set. Hopefully this will make it produce more accurate results!
I tuned the learning rate (The magnitude of how much it changes the weights, which is multiplied by the gradient of each weight to get the final change), added better printouts when training (Added a neat progress bar/tracking, output the loss, and a timer), and also using plotmatlib to plot the embeddings. The graph is how the model arranged each letter in space. What’s interesting is similar letters (like the ending character “.” and “e”, which both are commonly found near the end of the word) are in similar spots, so the model has sorted out some sort of meaning from their placements, which I think is pretty cool. The names are still quite nonsensicle, I think I might have to enlarge the model a little bit to improve performance, which means waiting longer for it to train :(
I made a bunch of little improvements, including increasing the character encodings to 10 dimensions up from 2, increasing the epochs to 200,000, and also decreasing the learning rate from .1 to .01 for the laster 50,000 epochs. Although the loss is significantly lower than Andrej Karpathy’s makemore (which I modeled my model after), it’s names are worse. Karpathy got 2.17 ish on the testing dataset, while I got 1.776. However, Karpathy’s generated slightly abnormal but reasonably word-like names, like “jeron” and “ham” while mine where a little more random (“xxxhorlis” is one of them). I’m not sure how to improve from here, I don’t think increasing the epochs will do much, it already took around 10 minutes to train this model, I think we’ll get diminishing returns. I will, as always, continue on to the next video in Karpathy’s series, hoping that his tips will help improve it.
I worked on switching to a Jupyter notebook instead of just a python file, this made it easier since I didn’t have to constantly retrain the model, and also could print out stuff in line. I also added batch normalization, which helps change the range (really the standard deviation) of the values before going into the activation function (tanh) so that the values are more spread out. tanh squishes all values between -1 and 1, so if all of the numbers are greater than 1 or less than -1, then all of the values will essentially be squished to either -1 or 1, which makes the model lose a lot of the data. But if you divide all the numbers so that they are all closer to 0, then the activation function is a lot more spread out and the data is preserved. (I got the photo from google, I think it’s helpful when visualizing it).
I was playing around with how changing the number of epochs/other variable affected the output, and seeing how that differed to before I implemented Batch normalization, and so tried to put the epochs up a lot. I ended up training it for 20,000,000 epochs, which took like 8 hours, which is why this devlog has so much time logged. It didn’t really improve it much, you can see by the loss graph it didn’t go down very much at all, so I’ll need to change something in how the code works. It was still fun though.
Put my model into the Layer class, so I can easily create lots of layers. The graph shows the activation distribution by layer. Each layer is pretty similar, as you can see. This devlog marks the end of the fourth lecture in Andrej Karpathy’s makemore series, out of 7, so we’re getting there! That’s just under 8 hours or lecture watched (so I spend roughly 5 minutes coding for every minute of lecture watched). Pretty interesting.
Added a demo page! You can check it out here: https://luchik28.github.io/BadGPT/ . I saved the model weights, built a script that reconstructs the model using those weights, and hosted it using github pages.
I followed Karpathy’s lecture on backpropagation, where he implemented backpropagation manually. In the series, he’s using Pytorch, which does it for you, which is why he’s doing it manually. I’m not using Pytorch, so the only way to do it is to do it manually, so I didn’t get to add too much to the code, I just verified that I had implemented it correctly and learned a bunch. It is still pretty confusing though, and I couldn’t solve any of the exercises in the lecture without watching his explanations. Anyway here’s a name it generated that I think is pretty cool.
I did a bunch of things to prep for implementing a wavenet architecture, which basically changes the model so instead of taking in all the characters of input at once and squishing them all into the first layer, it gradually puts them in at each separate layer. First, I put more stuff in classes! This didn’t really change the functionality, but instead of embedding the characters and flattening the model in separate chunks, I put them in their own classes so they can get put in the list of layers, and we can just run the input through each layer in the list, and compare it with the target at the end, instead of having half the layers in the list and half as separate chunks, which is a lot smoother. So the entire model is just: model = Sequential ([ Embedding ( vocab_size , n_embd ), FlattenConsecutive ( 2 ), Linear ( n_embd * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), FlattenConsecutive ( 2 ), Linear ( n_hidden * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), FlattenConsecutive ( 2 ), Linear ( n_hidden * 2 , n_hidden , bias = False ), BatchNorm1D ( n_hidden ), Tanh (), Linear ( n_hidden , vocab_size ), ]) Which I think is really cool. I also improved the loss graph, previously it looked like the screenshot on the right, because each iteration’s loss is graphed. Because our batch size is 32, which means in each iteration we look at just 32 inputs/output, a good deal of what the loss will be depends on how lucky we are with the input/output. Over a great number of iterations, it averages out into the correct value, though, so to fix the graph, we instead plot the average of every 1000 iterations, which lets us see a lot more detail that otherwise would be lost in the noise (the two loss graphs I added are not of the same model, but you get the idea). Anyway now I’m going to actually implement the wavenet architecture!
Implemented the wavenet architecture. Usually, during the flattening phase, the tensor goes from the shape (batch num, block size, embedding dimensions) to (batch num, block size * embedding dimensions). This squishes all of the embedded characters into one dimension. Wavenet does that more gradually, it slowly merges the different letters. So the first two letter embeddings get squished into one, then the next two, etc, and in the next layer then you have the first 4, then the next four, until by the final layer you have just one group of all the letters, which is the same as the original method, just a much more gradual approach. The first image is the training loss, the huge cliff is when the learning rate decreased. The second image is a visualization of the wavenet architecture from the paper. You can see that in each layer, nearby groups of input get merged together. In the original method, the graph would look like all of the inputs going to the 1st dot in the hidden layer, then continuing up. Next I will be actually building a GPT instead of this names project.
Trained the wavenet architecture on a file with just shakespear in it. It’s got the structure down well, and sometimes can do words and wordlike outputs, but generally spouts straight gibberish. I will try to follow a lecture to build a better Tokenizer and Transformer next time. Right now each character is treated as a token, and embedded into 10 dimensions, it would be better if pairs of characters were treated as tokens and embedded. Increasing the context size could also help, it’s currently an input of the previous 8 characters and outputting 1. This is it’s output:
I increased the block size from 8 characters to 64. This means that instead of the model taking in the previous 8 characters and outputting the next one, it takes in the previous 64 characters and outputs the next. This means that it should be able to keep track of longer words so it doesn’t get lost in them. However, it doesn’t seem to be improving the model too much, although that might be because I haven’t trained it as much as the others. I’ve done roughly 200,000 epochs, which took a long time, since this model is much larger (110,415 parameters vs 45,000), and has 6 hidden layers as apposed to 2, which means it is a lot slower. As you can see in the loss graph, it probably could make further gains, although it seems to be mostly good.
I implemented self attention! I will try to explain here, but will do a terrible job: basically, what that is, is it lets the model decide what tokens in the input are more important than the others. The first thing I did was scrap the wavenet model, and switched to a simple bigram model. The second thing I implemented was bag of words, which edits the input tokens so every element is the average of that element and all that came before it. This lets all of the tokens “talk” to eachother. This is all fine and dandy but since all the things are averaged then you don’t know where things came from, and positional data is lost, so we lose a lot of resolution and data, so that sucks. So we have to encode positional data. So instead of just averaging all the elements that came before, we expand each averaged element into a list, which has all the elements in a row instead of averaging them into one number. So the first row could be [1, 0, 0] and the second [1, 2, 0] and the third [1, 2, 3], etc. We do this by masking it with the tril function, from numpy (very cool). But this is problematic, because all of the elements are given the exact same weight. A letter 34 characters back gets the same weight as the last character in the input (which is the letter immediately preceding the predicted letter, the output). To fix this, we add self attention! This is modeled after the groundbreaking paper Attention is All You Need, which started the whole AI hype thing. How it works is each token has a linear layer (that multiplies it by learned weights) called the key, and another called the query. The query is kind of like what that token is looking for, and the key is kind of like what that token has. And these can be multiplied with the keys and queries of all the other tokens, and that lets you know which token has the stuff that the most other tokens are looking for, and is thus more important and can be given more weight. That is a single head of attention, there are multiple heads that can specialize in different things. This, in theory, should increase performance. But it also drastically increases the amount of time it takes to train. The model only has ~56k parameters, which is less than half of the wavenet model, but takes a lot more time to do it’s thing. This is the output from the results of more than 13 hours of training. As you can see from the loss function, the loss was decreasing at a steady rate, so more training could probably improve it. Plus, this was at a highish learning rate the whole time (.1) so decreasing it would probably further improve it. But I can’t do anything on my computer while this is training or it runs out of RAM, and I have to use my computer now, so I will be moving on for now.
I made a bunch of tiny improvements. I didn’t change the architecture at all, but I did change the optimizer to AdamW. The optimizer is what controls how much each parameter is changed each epoch. Before, I was using a set learning rate, of about .1 for the first 80% of training then decreasing to .01 for the last 20%. Decreasing it at the end is important because as the loss settles into a local minimum, it might not be able to go to the lowest point because it keeps overshooting it since the lr is too high. Conversely, we can’t keep the lr too small the whole time because it might settle into a very tiny local minima that it might have been able to go over with a higher learning rate. It would also take forever. AdamW helps improve the optimizing step by changing the learning rate per parameter, helping the model train as fast as possible without overfitting. Overfitting isn’t really an issue I’m worrying about since my model is pretty small (around 56k params), so it’s not really large enough to learn the ins and outs of my dataset. Anyway I also changed the logging step, so it now logs validation dataset loss in addition to the training dataset loss. I split the dataset into train and validation so I can make sure it’s not overfitting. Currently the val loss is at 1.76, which is a lot better than where we were at before, which makes me hopeful. Training has around another 7,000 epochs to go, but Stardance is yelling at me I should write another devlog now so here you go, Stardance. I’m looking forward to sampling the model and seeing how much it’s improved!
I finished training it! It finished with a val loss of around 1.76, it got down to 1.73 but ticked up at the end. The output is pretty good, but not substantially better than the wavenet model. However, it’s vaguely word-like, and took 20 hours to train so I’m not sure how much larger I can make the model before my laptop implodes. Next I will probably try to find a question-answer training dataset, so that I can start training it to answer questions. This step that I’ve been working on is the pre-training step, where I teach the model to basically spit out documents. Next, I have to have it spit out documents that happen to be question-answer documents.
Updated the demo website to include the wavenet model, and the new self-attention shakespear model. You can check it out here .
Started working on a more advanced tokenizer. The tokenizer is what splits the input text from words into numbers, and back again. Before, I was using a 10 dimensional embedding, where each letter is represented by a 10 long array (each value representing a dimension). But current models have much more advanced tokenizers, which often encompass entire words, or parts of words for longer words. This works using Byte Pair Encoding, which turns all of the letters pairs of letters into their utf encodings (usually 8), then iteratively merging the most common consecutive pairs into tokens to add to the vocabulary. You can see how tokenizers work at https://tiktokenizer.vercel.app/ , which is a cool website that lets you play around with stuff like that.
Switched to using the fineweb edu dataset, instead of shakespear. This is the dataset I will use to train my actual model on. It’s a highly currated database of the internet, and is similar to what GPT2 was trained on (although the actual db they trained it on is closed source). I also reformated the sampling system so you can put in a query and get a response, as long as the query takes up less tokens than the context. Other than swapping out the training file, it’s the exact same. Next, I will probably implement a special ending token to my tokenizer, and also increase the scale of my model a little bit. I can’t increase it all the way to what Karpathy does in his tutorial (he uses cloud computing, so he paid to rent out like 8 64GB GPUs, or something like that), since I don’t want to spend money training it. However I think I can squeeze a little more out of my laptop.
Added an EOS ID, which is a special token that the model can output to indicate that it’s done. I built a script to insert this in between passages in the training data, so it can learn when it should shut up (otherwise it will yap forever, until it hits the max number of output tokens). This meant I had to retrain the entire model, but got it down to a loss of around 3.46. Obviously, it’s not very good. But I’m pretty sure the only way to improve is to scale up the model size and training time, something I don’t really have the capacity to do (this model trained for 15 hours on my laptop). I will probably continue by adding this model to my demo website, and build a chatGPT like UI, just for fun. After that, I think it might be time to ship!
Trained the model a little more, exported it, wrote some UI to make it look more like a chatbot. It still sounds like gibberish. Sometimes I imagine that it’s output changes slightly depending on the context (for example, more numbers if I ask it a number related question, and a list if I ask it for a list, etc), but I’m probably just imagining it, it’s really just gibberish. Still kinda cool tho. You can check out the demo at https://luchik28.github.io/BadGPT/ .
Fixed up the readme a bit in preparation to ship. Specifically, I added info on what all the files do, but I named them poorly and then forgot what most of them do so it’s kind of confusing.
Ships:
badGPT is a conglomeration of sequential ML projects I did this summer, culminating in a chatbot like ChatGPT or Claude built from scratch using just python and numpy. I started off by building a name generation model, then a Shakespeare writing model, then finally a chatGPT-esque model. The model produces, for the most part, complete gibberish, so this was less a practical project and more an exercise in understanding how everything works. It performs so poorly because it’s so small. Models need a lot of parameters to be able to capture all the nuances required to produce coherent text, which makes the models much slower to train. The final model I made includes around 120,000 parameters, 4 transformer blocks of 4 attention heads each, and 64 tokens of context. It’s based largely on GPT-2, which for reference had about 1.5 billion parameters. Current frontier models, like Anthropic’s fable, have trillions of parameters and can have millions of input tokens, so it makes sense that my model is too small to make much sense at all. Even at its small size, it took my laptop more than 20 hours to train, so scaling up with my current hardware is not feasible. Many people like using libraries like pytorch and tensorflow, which include classes that handle backpropagation (the system that’s at the heart of letting the models learn), but I wanted to start from scratch so I wrote my own. If you wish to try any of my models out, you can visit the demo website (click try project), and click through the tabs to see each of the models. It all runs in your browser. You can also look through the Jupyter notebooks in the Github repository to get a sense of how everything works....
|
1793771239.7279682
|
1794635239.7279682
|
|
19165
|
Frictionless by @pranjal_ok | Stardance
|
pranjal_ok
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @pranjal_ok | Stardance
|
1793562497.3727734
|
1794167297.3727734
|
|
19166
|
n/a by @resslr | Stardance
|
resslr
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: n/a by @resslr | Stardance
|
1793789608.3151758
|
1794394408.3151758
|
|
19167
|
Custom Stardance API by @The_Craw | Stardance
|
The_Craw
|
1
|
4.33
|
36
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-16T12:47:45Z", "hours": 4.0, "multiplier": 9.67, "payout": 36, "blessing": "neutral", "text": "Stardance API is my own attempt at making Stardance Projects queryable. Because the official Stardance API isn’t released yet, this serves as a bridge between that and no API at all.", "repo": "https://github.com/Jonah-Crawford/Stardance-API", "demo": "https://stardance-api.ultimatecraw.xyz/docs"}]...
|
[{"post_id": 45045, "ts": "202 [{"post_id": 45045, "ts": "2026-08-11T09:07:07Z", "hours": 0.3306, "text": "I’m back from camping! (RIP my 60+ day streak) My plans going forward immediately is improving program counter modifications to allow for higher-level concepts to be bootstrapped onto Crawssembly instruction sets. (Image unrelated)"}, {"post_id": 9877, "ts": "2026-06-16T10:56:13Z", "hours": 1.5172, "text": "Finished the quirks, history now works properly."}, {"post_id": 9288, "ts": "2026-06-15T16:20:54Z", "hours": 0.5208, "text": "Added a history marker. Every pass will add to a history logger, so data over time can be tracked"}, {"post_id": 9267, "ts": "2026-06-15T15:42:44Z", "hours": 0.9881, "text": "The database now scrapes stardance every 6 hours"}, {"post_id": 9230, "ts": "2026-06-15T14:37:39Z", "hours": 0.6647, "text": "Barebones FastAPI website made for SDAPI"}]...
|
Title: Custom Stardance API by @The_Craw | Stardan Title: Custom Stardance API by @The_Craw | Stardance
Devlogs:
Barebones FastAPI website made for SDAPI
The database now scrapes stardance every 6 hours
Added a history marker. Every pass will add to a history logger, so data over time can be tracked
Finished the quirks, history now works properly.
I’m back from camping! (RIP my 60+ day streak) My plans going forward immediately is improving program counter modifications to allow for higher-level concepts to be bootstrapped onto Crawssembly instruction sets. (Image unrelated)
Ships:
Stardance API is my own attempt at making Stardance Projects queryable. Because the official Stardance API isn’t released yet, this serves as a bridge between that and no API at all....
|
1793843664.6360073
|
1793930064.6360073
|
|
19168
|
Frictionless by @matirobs | Stardance
|
matirobs
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @matirobs | Stardance
|
1793414863.788404
|
1794019663.788404
|
|
19169
|
AirWrite Studio by @priyajitk | Stardance
|
priyajitk
|
1
|
4.7
|
1
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-21T14:46:28Z", "hours": 1.0, "multiplier": 1.86, "payout": 1, "blessing": "neutral", "text": "AirWrite Studio is a real-time, hands-free spatial drawing platform I built using Python, PyQt6, MediaPipe, OpenCV, and offline AI tooling. The idea behind the project was simple: I wanted to make digital whiteboarding and creative interaction feel more natural and frictionless without depending on expensive hardware like drawing tablets, styluses, or touchscreens. The application transforms a standard webcam into a gesture-controlled digital canvas where users can draw, erase, select, move, and manipulate content entirely through hand gestures and voice commands. Instead of adapting ourselves to traditional input devices, I wanted the interface to adapt to human movement. One of the biggest quality-of-life improvements is the completely hardware-free interaction system. Users can simply sit in front of a webcam and interact with the canvas naturally in mid-air. I also implemented smart geometry and OCR features that automatically clean up rough sketches into proper geometric shapes and convert handwritten strokes into editable text. During testing, this genuinely made brainstorming and diagramming feel much smoother because users didn’t have to waste time fixing messy sketches manually. Another major feature I’m proud of is the multimodal accessibility system. Alongside gesture controls, the project integrates offline voice commands using Vosk, allowing users to execute actions like “undo,” “clear,” or change colors without touching the keyboard or mouse. I wanted the experience to feel seamless and accessible, especially for presentations, teaching environments, and users who may struggle with traditional input devices. The hardest part of the project was making the interaction system feel stable and intentional. Human gestures are naturally inconsistent, and early prototypes constantly suffered from accidental triggers and jittery movement. A huge amount of time went into smoothing gesture input, tuning confidence thresholds, and implementing filters like the One Euro Filter so the controls would feel responsive without becoming chaotic. I also had to optimize performance carefully because the application simultaneously handles real-time computer vision inference, OpenGL rendering, OCR processing, gesture recognition, and UI updates. What I’m most proud of is how natural the final interaction feels. Gestures like pinching to draw, making a fist to erase, or pointing to lasso-select objects became surprisingly intuitive after enough iteration. I also spent a lot of time polishing the UI because I didn’t want the project to feel like a rough prototype. The interface takes inspiration from modern minimalist tools like Linear and Notion, with a restrained dark aesthetic that keeps the focus on the spatial interaction itself. The project can be tested using a standard webcam and a Python 3 environment. After cloning the repository and installing dependencies through pip install -r requirements.txt , the app can be launched using python main.py . Optional integrations include Tesseract for OCR functionality and Vosk with PyAudio for offline voice commands. Once the camera starts, users can interact entirely through gestures: Pinch thumb and index finger together to draw Make a fist to erase Point with the index finger to select objects Use multi-finger gestures to drag content Keep an open palm to remain in neutral mode There’s also a smart shape mode that automatically converts rough freehand sketches into clean geometry in real time, which ended up becoming one of my favorite parts of the entire project. Overall, AirWrite Studio was my attempt to explore what frictionless spatial computing could look like using only commodity hardware and open-source technologies. I wanted it to feel practical, accessible, and genuinely useful rather than just a flashy computer vision demo.", "repo": "https://github.com/pk2010-ux/AirWriteStudio", "demo": "https://github.com/pk2010-ux/AirWriteStudio/releases/tag/v1.0.0"}]...
|
[{"post_id": 30599, "ts": "202 [{"post_id": 30599, "ts": "2026-07-18T09:38:41Z", "hours": 2.4131, "text": "New Logo For AirWrite Studio Hi viewers! As you can see, i have added a new logo for the project. Please suggest any edits if you want!"}, {"post_id": 16977, "ts": "2026-06-27T15:44:25Z", "hours": 1.2839, "text": "Hello Everyone! I have been working on this project since two months, now. And finally with the help of the Hack Club Tester Team, I am Finally able to make a final release of this Project. I have also updated the demo link so that you all can now directly download a .exe file without any problem. At first you may see a warning as I have not bought a certificate for the .exe program but you can click on Run Anyway to use it. But if you still want a web one navigate here"}, {"post_id": 12020, "ts": "2026-06-19T16:39:25Z", "hours": 0.8261, "text": "AirWrite Studio — Devlog Overview AirWrite Studio is a hands-free digital canvas built with Python and PyQt6. It uses webcam-based hand tracking and gesture detection to let users draw, erase, select, and manipulate canvas content without a mouse or stylus. Current Status Core application structure is in place with main.py , UI modules, tracking modules, and canvas rendering. Hand gestures are detected and mapped to canvas actions through MediaPipe landmark tracking. Gesture control covers drawing, erasing, object selection, dragging, scaling, and neutral/stop states. Voice command support is planned via Vosk and the tracking/voice_commander.py module. The canvas supports export formats and workspace management via native file handling. Features Implemented Gesture-based drawing and erasing Shape recognition and smart geometry snapping Text conversion support using OCR integration pathways Grid templates and presentation-friendly laser/highlighter modes Undo/redo history architecture Clean dark UI layout using PyQt6 widgets and custom styling Project Structure main.py — Application entry point config.py , utils.py — configuration and helper utilities canvas/ — canvas engine, widgets, object rendering, serialization, shape recognition, export tracking/ — hand tracker, gesture detector, smoother, voice commander ui/ — main window, sidebar, camera widget, toast notifications, styles assets/ — model files, Vosk speech resources, hand landmarker task files Recent Work Built the main interactive canvas and stabilized gesture interactions. Added smart UI for tool selection and camera control. Integrated offline voice command support architecture with Vosk assets. Added documentation in README.md to describe features, installation, and usage. Created a web-based demo version using Flask and Hugging Face Spaces Docker deployment. Note: The web demo relies on server-side processing for MediaPipe gestures and may experience latency or glitchiness depending on the user’s hardware limitations, webcam quality, and network speed. Challenges Ensuring reliable hand detection across different lighting conditions and webcams. Mapping natural gestures into consistent canvas commands without accidental triggers. Keeping performance smooth for real-time drawing and gesture recognition. Handling network latency and server-side model processing for the web demo without native client-side binaries. Next Milestones Finalize gesture calibration and user feedback flow. Complete OCR text conversion and editable text object workflow. Add full export support for PNG, PDF, SVG, and native .air saves. Polish the UI, including toolbar behavior, status indicators, and onboarding hints. Add tests for canvas serialization and gesture classification. Notes for Future Development Add a requirements-dev.txt for development tooling, formatting, and testing. Consider adding a CHANGELOG.md or release notes for future version tracking. Keep venv/ and __pycache__/ ignored in source control, and preserve only source files and assets."}, {"post_id": 9227, "ts": "2026-06-15T14:33:11Z", "hours": 0.3142, "text": "AirWrite Studio - Devlog AirWrite Studio is a hands-free digital canvas built using Python, PyQt6, and MediaPipe. The idea behind the project is to allow users to draw, erase, select, and manipulate objects on a digital canvas entirely through hand gestures detected via a webcam. The core structure of the application is now functional. The project currently includes the main application window, canvas rendering system, tracking modules, UI components, and asset management. Real-time hand tracking is handled through MediaPipe landmark detection, which is then translated into different canvas actions. Several gesture interactions are already implemented. Users can draw using a thumb-and-index pinch gesture, erase using a fist gesture, select objects using a pointing gesture, and drag or scale objects using multi-finger gestures. An open palm acts as a neutral or stop state to reduce accidental interactions. A major focus during development has been making gesture controls feel natural and stable. Small hand movements, lighting changes, and different webcam qualities often create false triggers or unstable tracking, so additional smoothing and gesture filtering logic has been added to improve consistency during real-time interaction. The canvas system already supports freehand drawing, object movement, shape recognition, and undo/redo architecture. Smart shape snapping can detect rough circles, rectangles, triangles, and straight lines and convert them into cleaner geometry automatically. Additional drawing tools have also been added, including: highlighter mode laser pointer mode grid templates customizable pen settings dark themed UI styling The project also includes the architecture for OCR text conversion and offline voice command support. OCR integration pathways are connected for future editable text workflows, while the voice command system is being developed using Vosk through the tracking/voice_commander.py module. The repository is currently organized into separate modules for better maintainability: main.py handles application startup canvas/ contains rendering, serialization, export, and shape recognition systems tracking/ contains hand tracking, gesture detection, smoothing, and voice command modules ui/ contains interface components such as the sidebar, camera widget, and notifications assets/ stores speech models and hand tracking resources Recent development work focused on stabilizing gesture interactions, improving the canvas workflow, refining the UI layout, and integrating voice command resources. Documentation was also added through the README.md file to explain installation, features, and project usage. One of the biggest challenges so far has been balancing responsiveness with stability. Gesture systems need to react quickly without triggering unintended actions from natural hand movement. Maintaining smooth performance while simultaneously handling camera input, landmark processing, UI rendering, and drawing operations has also required ongoing optimization. The next stage of development will focus on: finalizing gesture calibration completing OCR text conversion workflows adding full PNG, PDF, SVG, and .air export support polishing onboarding and status indicators adding automated tests for serialization and gesture classification Future improvements may also include a dedicated requirements-dev.txt , release tracking through a CHANGELOG.md , and additional development tooling for testing and formatting. The project has now reached a stage where the core systems are functional and connected together. Most upcoming work will focus on refinement, optimization, and improving overall usability. Which is usually the phase where software projects politely reveal twice as many problems as originally expected."}]...
|
Title: AirWrite Studio by @priyajitk | Stardance
Title: AirWrite Studio by @priyajitk | Stardance
Devlogs:
AirWrite Studio - Devlog AirWrite Studio is a hands-free digital canvas built using Python, PyQt6, and MediaPipe. The idea behind the project is to allow users to draw, erase, select, and manipulate objects on a digital canvas entirely through hand gestures detected via a webcam. The core structure of the application is now functional. The project currently includes the main application window, canvas rendering system, tracking modules, UI components, and asset management. Real-time hand tracking is handled through MediaPipe landmark detection, which is then translated into different canvas actions. Several gesture interactions are already implemented. Users can draw using a thumb-and-index pinch gesture, erase using a fist gesture, select objects using a pointing gesture, and drag or scale objects using multi-finger gestures. An open palm acts as a neutral or stop state to reduce accidental interactions. A major focus during development has been making gesture controls feel natural and stable. Small hand movements, lighting changes, and different webcam qualities often create false triggers or unstable tracking, so additional smoothing and gesture filtering logic has been added to improve consistency during real-time interaction. The canvas system already supports freehand drawing, object movement, shape recognition, and undo/redo architecture. Smart shape snapping can detect rough circles, rectangles, triangles, and straight lines and convert them into cleaner geometry automatically. Additional drawing tools have also been added, including: highlighter mode laser pointer mode grid templates customizable pen settings dark themed UI styling The project also includes the architecture for OCR text conversion and offline voice command support. OCR integration pathways are connected for future editable text workflows, while the voice command system is being developed using Vosk through the tracking/voice_commander.py module. The repository is currently organized into separate modules for better maintainability: main.py handles application startup canvas/ contains rendering, serialization, export, and shape recognition systems tracking/ contains hand tracking, gesture detection, smoothing, and voice command modules ui/ contains interface components such as the sidebar, camera widget, and notifications assets/ stores speech models and hand tracking resources Recent development work focused on stabilizing gesture interactions, improving the canvas workflow, refining the UI layout, and integrating voice command resources. Documentation was also added through the README.md file to explain installation, features, and project usage. One of the biggest challenges so far has been balancing responsiveness with stability. Gesture systems need to react quickly without triggering unintended actions from natural hand movement. Maintaining smooth performance while simultaneously handling camera input, landmark processing, UI rendering, and drawing operations has also required ongoing optimization. The next stage of development will focus on: finalizing gesture calibration completing OCR text conversion workflows adding full PNG, PDF, SVG, and .air export support polishing onboarding and status indicators adding automated tests for serialization and gesture classification Future improvements may also include a dedicated requirements-dev.txt , release tracking through a CHANGELOG.md , and additional development tooling for testing and formatting. The project has now reached a stage where the core systems are functional and connected together. Most upcoming work will focus on refinement, optimization, and improving overall usability. Which is usually the phase where software projects politely reveal twice as many problems as originally expected.
AirWrite Studio — Devlog Overview AirWrite Studio is a hands-free digital canvas built with Python and PyQt6. It uses webcam-based hand tracking and gesture detection to let users draw, erase, select, and manipulate canvas content without a mouse or stylus. Current Status Core application structure is in place with main.py , UI modules, tracking modules, and canvas rendering. Hand gestures are detected and mapped to canvas actions through MediaPipe landmark tracking. Gesture control covers drawing, erasing, object selection, dragging, scaling, and neutral/stop states. Voice command support is planned via Vosk and the tracking/voice_commander.py module. The canvas supports export formats and workspace management via native file handling. Features Implemented Gesture-based drawing and erasing Shape recognition and smart geometry snapping Text conversion support using OCR integration pathways Grid templates and presentation-friendly laser/highlighter modes Undo/redo history architecture Clean dark UI layout using PyQt6 widgets and custom styling Project Structure main.py — Application entry point config.py , utils.py — configuration and helper utilities canvas/ — canvas engine, widgets, object rendering, serialization, shape recognition, export tracking/ — hand tracker, gesture detector, smoother, voice commander ui/ — main window, sidebar, camera widget, toast notifications, styles assets/ — model files, Vosk speech resources, hand landmarker task files Recent Work Built the main interactive canvas and stabilized gesture interactions. Added smart UI for tool selection and camera control. Integrated offline voice command support architecture with Vosk assets. Added documentation in README.md to describe features, installation, and usage. Created a web-based demo version using Flask and Hugging Face Spaces Docker deployment. Note: The web demo relies on server-side processing for MediaPipe gestures and may experience latency or glitchiness depending on the user’s hardware limitations, webcam quality, and network speed. Challenges Ensuring reliable hand detection across different lighting conditions and webcams. Mapping natural gestures into consistent canvas commands without accidental triggers. Keeping performance smooth for real-time drawing and gesture recognition. Handling network latency and server-side model processing for the web demo without native client-side binaries. Next Milestones Finalize gesture calibration and user feedback flow. Complete OCR text conversion and editable text object workflow. Add full export support for PNG, PDF, SVG, and native .air saves. Polish the UI, including toolbar behavior, status indicators, and onboarding hints. Add tests for canvas serialization and gesture classification. Notes for Future Development Add a requirements-dev.txt for development tooling, formatting, and testing. Consider adding a CHANGELOG.md or release notes for future version tracking. Keep venv/ and __pycache__/ ignored in source control, and preserve only source files and assets.
Hello Everyone! I have been working on this project since two months, now. And finally with the help of the Hack Club Tester Team, I am Finally able to make a final release of this Project. I have also updated the demo link so that you all can now directly download a .exe file without any problem. At first you may see a warning as I have not bought a certificate for the .exe program but you can click on Run Anyway to use it. But if you still want a web one navigate here
New Logo For AirWrite Studio Hi viewers! As you can see, i have added a new logo for the project. Please suggest any edits if you want!
Ships:
AirWrite Studio is a real-time, hands-free spatial drawing platform I built using Python, PyQt6, MediaPipe, OpenCV, and offline AI tooling. The idea behind the project was simple: I wanted to make digital whiteboarding and creative interaction feel more natural and frictionless without depending on expensive hardware like drawing tablets, styluses, or touchscreens. The application transforms a standard webcam into a gesture-controlled digital canvas where users can draw, erase, select, move, and manipulate content entirely through hand gestures and voice commands. Instead of adapting ourselves to traditional input devices, I wanted the interface to adapt to human movement. One of the biggest quality-of-life improvements is the completely hardware-free interaction system. Users can simply sit in front of a webcam and interact with the canvas naturally in mid-air. I also implemented smart geometry and OCR features that automatically clean up rough sketches into proper geometric shapes and convert handwritten strokes into editable text. During testing, this genuinely made brainstorming and diagramming feel much smoother because users didn’t have to waste time fixing messy sketches manually. Another major feature I’m proud of is the multimodal accessibility system. Alongside gesture controls, the project integrates offline voice commands using Vosk, allowing users to execute actions like “undo,” “clear,” or change colors without touching the keyboard or mouse. I wanted the experience to feel seamless and accessible, especially for presentations, teaching environments, and users who may struggle with traditional input devices. The hardest part of the project was making the interaction system feel stable and intentional. Human gestures are naturally inconsistent, and early prototypes constantly suffered from accidental triggers and jittery movement. A huge amount of time went into smoothing gesture input, tuning confidence thresholds, and implementing filters like the One Euro Filter so the controls would feel responsive without becoming chaotic. I also had to optimize performance carefully because the application simultaneously handles real-time computer vision inference, OpenGL rendering, OCR processing, gesture recognition, and UI updates. What I’m most proud of is how natural the final interaction feels. Gestures like pinching to draw, making a fist to erase, or pointing to lasso-select objects became surprisingly intuitive after enough iteration. I also spent a lot of time polishing the UI because I didn’t want the project to feel like a rough prototype. The interface takes inspiration from modern minimalist tools like Linear and Notion, with a restrained dark aesthetic that keeps the focus on the spatial interaction itself. The project can be tested using a standard webcam and a Python 3 environment. After cloning the repository and installing dependencies through pip install -r requirements.txt , the app can be launched using python main.py . Optional integrations include Tesseract for OCR functionality and Vosk with PyAudio for offline voice commands. Once the camera starts, users can interact entirely through gestures: Pinch thumb and index finger together to draw Make a fist to erase Point with the index finger to select objects Use multi-finger gestures to drag content Keep an open palm to remain in neutral mode There’s also a smart shape mode that automatically converts rough freehand sketches into clean geometry in real time, which ended up becoming one of my favorite parts of the entire project. Overall, AirWrite Studio was my attempt to explore what frictionless spatial computing could look like using only commodity hardware and open-source technologies. I wanted it to feel practical, accessible, and genuinely useful rather than just a flashy computer vision demo....
|
1793771386.885077
|
1794635386.885077
|
|
19170
|
ScrobbleDeck - Last.fm Widget by @abdipr | Stardan ScrobbleDeck - Last.fm Widget by @abdipr | Stardance...
|
abdipr
|
0
|
1.81
|
0
|
[]
|
[{"post_id": 22850, "ts": "202 [{"post_id": 22850, "ts": "2026-07-05T13:52:51Z", "hours": 1.8089, "text": "First time making widget embed! this is ScrobbleDeck, an unofficial Last.fm embedded widget!"}]...
|
Title: ScrobbleDeck - Last.fm Widget by @abdipr | Title: ScrobbleDeck - Last.fm Widget by @abdipr | Stardance
Devlogs:
First time making widget embed! this is ScrobbleDeck, an unofficial Last.fm embedded widget!...
|
1793534097.1993933
|
1794138897.1993933
|
|
19171
|
NULL
|
NULL
|
0
|
0.0
|
0
|
[]
|
[]
|
|
1793911720.6048503
|
1794775720.6048503
|
|
19172
|
My first slack bot! by @tripletuong | Stardance
|
tripletuong
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @tripletuong | Stard Title: My first slack bot! by @tripletuong | Stardance...
|
1793418796.1689966
|
1794023596.1689966
|
|
19173
|
Calculator by @nfhwkl | Stardance
|
nfhwkl
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Calculator by @nfhwkl | Stardance
|
1793342950.0311816
|
1793947750.0311816
|
|
19174
|
PitWall by @iva33 | Stardance
|
iva33
|
0
|
59.0
|
0
|
[]
|
[{"post_id": 37297, "ts": "202 [{"post_id": 37297, "ts": "2026-07-29T22:10:18Z", "hours": 8.0, "text": "PitWall Devlog 12 Rivalry Report, Circuit Evolution and Reliability Tracker What I built Rivalry Report Card get_rivalry_report combines session pace, consistency , and career h2h across circuits and years and puts it all together, chart_rivalry_report shows the two side by side using make_subplots Multi-Year Circuit Evolution get_circuit_evolution loops get_circuit_dna for a range of years for one circuit and then tracks how top speed and average corner speed change over time although when testing it you might see a spike somewhere which probably means that it was affected by rain Reliability/DNF Tracker get_reliability_tracker takes a season and tallies each driver’s finishing status per race into finishes, DNFs, and other non-finishes (DNS/DSQ or NC) Problems I hit Forgot to fix the lap filtering properly and it did ruin the consistency in the rivalry report function because it was a lap affected by traffic"}, {"post_id": 36062, "ts": "2026-07-27T22:16:37Z", "hours": 3.0, "text": "PitWall Devlog 10 Mini-Sector Dominance and Lap 1 Analysis What I built Mini-Sector Dominance Heatmap get_minisector_dominance splits a lap and figures out which driver had the highest average speed in each one chart_minisector_dominance shows it Lap 1 Analysis get_lap1_analysis compares grid position to position at the end of lap 1 to show how many places a driver gained after the start and the first lap as a whole basically chart_lap1_analysis shows it Anyway this is from the Hungarian gp which was last week:"}, {"post_id": 35824, "ts": "2026-07-27T14:44:21Z", "hours": 4.0, "text": "PitWall Devlog 9 Fuel Load Estimator and Undercut Calculator What I built Fuel Load Effect Estimator get_fuel_effect estimates how much lap time a driver gains from burning off fuel across a race, FastF1 doesn’t have a fuel sensor data, so this is an estimate so it’s not as precise as the actual data chart_fuel_effect compares the estimated fuel effect for a few drivers Undercut/Overcut Effectiveness Calculator get_undercut_effectiveness checks whether pitting earlier than a rival actually gained track position or gave them an advantage, finds when each driver pits, confirms driver1 actually pitted first, measures the time gap between them the lap before driver1 stops, then measures it again a few laps after the rival has also boxed, and the difference between those two numbers tells if the undercut worked although you won’t see this every race actually took me some time to think of an example so that i could test the function and it’s not always effective as you will have older tyres then chart_undercut_effectiveness shows the before/after gap"}, {"post_id": 35167, "ts": "2026-07-26T12:49:52Z", "hours": 5.0, "text": "PitWall Devlog 8 Tyre Strategy, and Corner Speeds What I built Tyre Strategy Comparison get_tyre_strategy takes a driver’s laps by stint and shows the used compound (medium, soft, hard, inter and so on) , start lap, end lap, and stint length. chart_tyre_strategy shows it compound by compound and also uses the tyre colors Corner Speed Analysis get_corner_speeds reuses the same logic from mistake detection, but instead of finding the nearest corner to one point, it finds the minimum speed near the apex chart_corner_speeds compares multiple drivers’ apex speed corner by corner for a quali lap also i started working on a fuel load estimator using TyreLife"}, {"post_id": 33585, "ts": "2026-07-23T17:03:58Z", "hours": 5.0, "text": "PitWall Devlog 7 New functions: DRS Effect Analyzer get_drs_effect checks where drs was used in a lap basically when the rear wing was open (drs zones) and calculates the speed gain within each one, entry speed vs peak Lap Time Delta Chart get_lap_delta compares two drivers’ laps by interpolating both onto the same distance grid using then subtracts one from the other at every point to get a time gap across the lap. Driver & Constructor Standings get_driver_standings and get_constructor_standings basically show the total points accumulated per team and per driver after a certain race A small issue the drs effect function doesn’t work for this year’s races because of the regulation changes and there isn’t exactly drs now but active aero but works for other years"}, {"post_id": 32549, "ts": "2026-07-21T20:07:15Z", "hours": 4.0, "text": "PitWall Devlog 6 - Championship Battle, Overtakes, and Track Evolution What I built Championship Battle Tracker get_championship_battle tracks points for a list of drivers during a season round by round and adds up the points also, tries to load a Sprint session for the same race if it exists it adds those points too, if not it just moves on since most weekends don’t have one. chart_championship_battle is the chart that shows it and it uses the team colors like the other charts and makes the line dashed if there are teammates Overtake Analyzer get_overtakes looks at every position swap between consecutive laps , for each pair of laps it takes everyone’s position and checks every pair of drivers to see if their order flipped, also i had to exclude inlaps and outlaps since when you pit usually you drop many positions get_overtake_summary is just a counter for the overtakes chart_overtakes shows it Track Evolution get_track_evolution looks at how the track itself gets faster as a session goes on, takes every driver’s laps together, sorts them by LapStartTime then tracks a running best lap and an average pace over a window chart_track_evolution visualises it Problems I hit i forgot to exclude inlaps basically the first lap out of the box when you warm the tires for the track_evolution function"}, {"post_id": 31795, "ts": "2026-07-20T13:54:59Z", "hours": 9.0, "text": "PitWall Devlog 5 Weather, Degradation, and Historical Performance What I built Weather Performance get_weather compares average qualifying position for a list of drivers across wet sessions vs. dry sessions and calculates a wet_advantage which is basically just dry avg minus wet avg so a positive number means someone performs better in the rain rather than in the dry. chart_weather visualises it Tire Degradation get_tire_degradation takes each stint and calculates lap-time loss per lap of tyre age. The laps are first filtered so that there are no inaccurate laps and that means excluding laps where there was a red flag, yellow/double yellows, exclude inlaps and outlaps and also if there was a safety car/vsc and also TyreLife > 2 to exclude also the first 2 laps of the stint where in general you have to nurse the tires to warm them up. chart_tire_degradation just visualises it. Teammate Gap get_teammate_gap compares best qualifying times between two teammates across a season. Because not every driver reaches Q3, it falls back Q3 - Q2 - Q1 to find each driver’s actual best time for that quali session. chart_teammate_gap visualises it, red or cyan depending on who was faster. Historical Performance get_fastest_lap_history finds the fastest lap from every quali session since 2018 as that’s how far the data goes. get_driver_circuit_stats does the same thing but for a driver, pulling qualifying position, race position, fastest lap, and finishing result for each year at a given circuit. Sector Times and Pit Stops get_sector_improvement breaks a driver’s sector times down by stint and tyre age, using the same filtering to exclude some laps as the degradation function, get_pitstop_performance calculates stop duration by matching a driver’s pit-in lap to their next pit-out lap, discarding anything under 15s or over 60s since those aren’t really representative. Career Head-to-Head get_h2h_career compares two drivers’ qualifying head-to-head win rate at specific circuits across multiple years, returns a win percentage per location. chart_h2h_career again visualises it. Problems I hit First pass on pit stop duration had no bounds so I was getting stops showing as 3s and 140s which were basically laps flagged as pit laps during safety car periods which is a lot shorter so I added the 15–60s filter also in general I had issues with how tidy the charts looked for example when looking at the stints, each stint is shown with the color of the compound so yellow for medium and so on and for some races which aren’t one stoppers you often use one compound more than once so I lowered the opacity if there is a second stint on the same compound, it’s not a perfect solution but it works"}, {"post_id": 29449, "ts": "2026-07-16T12:16:32Z", "hours": 6.0, "text": "PitWall Devlog 4 Circuit DNA and Qualifying Analysis What I built Qualifying Analysis get_quali_improvement tracks a driver’s best lap time across Q1, Q2 and Q3 using session.results which returns the results from the three sessions. chart_quali_improvement calculates each driver’s progression between 2 sessions (Q1 and Q2 and so on) get_perfect_lap gets its own chart chart_perfect_lap shows the perfect theoretical lap vs actual best lap where the best lap is the three fastest sectors overall per driver Circuit DNA It classifies a circuit based on its traits (power track, high/low df, high/low drag and so on) get_circuit_dna analyzes the fastest lap telemetry from any session and extracts 6 metrics: full throttle percentage, braking percentage, top speed, average corner speed, low speed corner percentage and high speed cornering percentage. classify_circuit uses those metrics to label a circuit as High Speed, Power Track, High Downforce, Stop/Go or Balanced. Tested across a few circuits as well chart_circuit_dna shows a radar chart overlaying multiple circuits so you can visually compare their personalities get_team_circuit_affinity and get_driver_circuit_affinity calculate average qualifying positions per team and driver based on circuit type Results Silverstone: High Speed — 65% full throttle, 162 km/h avg corner speed Monaco: High Downforce — 34% low speed corners, 27% braking ANT is the strongest qualifier across all circuit types in 2026 Mercedes dominant on Balanced circuits, Ferrari strong on High Speed Problems I hit FastF1 doesn’t support Q1/Q2/Q3 as separate session types so i had to use session.results which has cleaner segment times Circuit classifier kept misclassifying Silverstone as Power Track in the if/elif part of the code Team affinity chart showed each team 3 times in the legend fixed it with dict.fromkeys() to remove the duplicates"}, {"post_id": 27182, "ts": "2026-07-12T14:46:12Z", "hours": 8.0, "text": "PitWall Devlog 3 — Mistake Detector What I built Mistake Detector it compares a driver’s telemetry lap by lap at the same point on track. FastF1 gives car data sampled every few milliseconds but the points aren’t evenly spaced by distance, so I used scipy to interpolate both laps onto a common grid every 10 meters, then subtracted one speed trace from the other to find where time was lost. detect_mistakes finds every zone where speed dropped more than 5 km/h, calculates time lost using distance ÷ speed physics, and maps each mistake to the nearest turn number using FastF1’s circuit info. chart_track_mistakes draws the full circuit map colored by speed using matplotlib, green for fast, red for slow and with mistake zones highlighted and labeled with turn number and time lost. get_perfect_lap finds the best individual three sectors from all of a driver’s qualifying laps and combines them into the theoretical fastest possible lap, showing how much time they left on the table. chart_perfect_lap visualizes this as a grouped bar chart, green for perfect lap sectors, driver’s color for actual best lap. Results from British GP 2026 qualifying NOR had 5 mistake zones totalling 0.77 seconds lost between his best and second best lap. Biggest mistake at Turn 18 — 22.7 km/h speed loss, 0.31 seconds gone. Problems I hit Interpolation was the hardest concept to understand and implement, two laps have telemetry at different distance points so you can’t compare directly. scipy ’s interp1d solved it Had return fig accidentally inside a for loop in chart_race_pace and only the first stint would show up Also needed to fix charts where you’re comparing 2 drivers from the same team because they have the same color which makes the chart unreadable Also done this session Set up GitHub and pushed the code so far Changed the color scheme for the charts Fixed teammate differentiation across the charts"}, {"post_id": 20240, "ts": "2026-07-01T19:47:12Z", "hours": 4.0, "text": "PitWall Devlog 2 — Charts and Visualization Spent this week visualising the data itself and turning it into interactive charts. What I built chart_race_pace shows a driver’s lap times across the entire race with each stint colored by tire compound. Pit laps are shown as grey X markers so you can see the inlaps and outlaps. chart_head_to_head overlays two drivers’ pace on the same chart using their official team colors pulled directly from the session data. When comparing teammates who share a color, one line becomes dashed automatically. chart_consistency compares multiple drivers’ consistency scores as bars. A lower score means that the driver is more consistent. chart_quali_comparison breaks down each driver’s best qualifying lap into the three sectors side by side, instantly shows where one driver gained or lost time compared to another. chart_position_change tracks each driver’s position lap by lap through the race, starting from their actual grid position as lap 0 so position gains and losses are accurate. Problems I hit The position chart was showing drivers starting from the wrong position because FastF1 doesn’t always record lap 1 position data cleanly. Fixed it by pulling the grid position directly from the session info and showing it as lap 0. The teammate color logic also had to be rethought twice before landing on a simple used_colors list approach that works cleanly."}, {"post_id": 10803, "ts": "2026-06-17T18:40:43Z", "hours": 3.0, "text": "Devlog 1! As an f1 fan and motosports fan in general, I wanted to create something that I’m going to use myself pretty often and work with data that genuinely interests me which is why I’m creating PitWall, a website that analyses data using FastF1, an open source F1 data library. The main idea is to pull real F1 data and let people analyze race pace, quali laps, driver mistakes, simulate alternate race strategies. I’m also going to be using NASA atmospheric data to correlate weather conditions with lap time performance. Started off by working on analyze.py which for now has 5 functions as the core of the project: get_clean_lap which filters out sc, vsc laps, track limits and such get_race_pace calculates the average race pace per stint get_head_to_head combines 2 drivers’ laps into one table for comparison get_consistency_score uses standard deviation to measure the consistency get_h2h_summary compares 2 drivers’ pace and tells which one was faster I’ve also started working on charts.py to set up the dark F1 color theme and pulled the official team colors from the session data. I tested everything in the terminal, VER vs LEC in Australia 2023 showed that Verstappen’s pace was 1.667 seconds per laps faster on average. This here is Hamilton and Verstappen’s race pace in Mexico, 2022:"}]...
|
Title: PitWall by @iva33 | Stardance
Devlogs:
Dev Title: PitWall by @iva33 | Stardance
Devlogs:
Devlog 1! As an f1 fan and motosports fan in general, I wanted to create something that I’m going to use myself pretty often and work with data that genuinely interests me which is why I’m creating PitWall, a website that analyses data using FastF1, an open source F1 data library. The main idea is to pull real F1 data and let people analyze race pace, quali laps, driver mistakes, simulate alternate race strategies. I’m also going to be using NASA atmospheric data to correlate weather conditions with lap time performance. Started off by working on analyze.py which for now has 5 functions as the core of the project: get_clean_lap which filters out sc, vsc laps, track limits and such get_race_pace calculates the average race pace per stint get_head_to_head combines 2 drivers’ laps into one table for comparison get_consistency_score uses standard deviation to measure the consistency get_h2h_summary compares 2 drivers’ pace and tells which one was faster I’ve also started working on charts.py to set up the dark F1 color theme and pulled the official team colors from the session data. I tested everything in the terminal, VER vs LEC in Australia 2023 showed that Verstappen’s pace was 1.667 seconds per laps faster on average. This here is Hamilton and Verstappen’s race pace in Mexico, 2022:
PitWall Devlog 2 — Charts and Visualization Spent this week visualising the data itself and turning it into interactive charts. What I built chart_race_pace shows a driver’s lap times across the entire race with each stint colored by tire compound. Pit laps are shown as grey X markers so you can see the inlaps and outlaps. chart_head_to_head overlays two drivers’ pace on the same chart using their official team colors pulled directly from the session data. When comparing teammates who share a color, one line becomes dashed automatically. chart_consistency compares multiple drivers’ consistency scores as bars. A lower score means that the driver is more consistent. chart_quali_comparison breaks down each driver’s best qualifying lap into the three sectors side by side, instantly shows where one driver gained or lost time compared to another. chart_position_change tracks each driver’s position lap by lap through the race, starting from their actual grid position as lap 0 so position gains and losses are accurate. Problems I hit The position chart was showing drivers starting from the wrong position because FastF1 doesn’t always record lap 1 position data cleanly. Fixed it by pulling the grid position directly from the session info and showing it as lap 0. The teammate color logic also had to be rethought twice before landing on a simple used_colors list approach that works cleanly.
PitWall Devlog 3 — Mistake Detector What I built Mistake Detector it compares a driver’s telemetry lap by lap at the same point on track. FastF1 gives car data sampled every few milliseconds but the points aren’t evenly spaced by distance, so I used scipy to interpolate both laps onto a common grid every 10 meters, then subtracted one speed trace from the other to find where time was lost. detect_mistakes finds every zone where speed dropped more than 5 km/h, calculates time lost using distance ÷ speed physics, and maps each mistake to the nearest turn number using FastF1’s circuit info. chart_track_mistakes draws the full circuit map colored by speed using matplotlib, green for fast, red for slow and with mistake zones highlighted and labeled with turn number and time lost. get_perfect_lap finds the best individual three sectors from all of a driver’s qualifying laps and combines them into the theoretical fastest possible lap, showing how much time they left on the table. chart_perfect_lap visualizes this as a grouped bar chart, green for perfect lap sectors, driver’s color for actual best lap. Results from British GP 2026 qualifying NOR had 5 mistake zones totalling 0.77 seconds lost between his best and second best lap. Biggest mistake at Turn 18 — 22.7 km/h speed loss, 0.31 seconds gone. Problems I hit Interpolation was the hardest concept to understand and implement, two laps have telemetry at different distance points so you can’t compare directly. scipy ’s interp1d solved it Had return fig accidentally inside a for loop in chart_race_pace and only the first stint would show up Also needed to fix charts where you’re comparing 2 drivers from the same team because they have the same color which makes the chart unreadable Also done this session Set up GitHub and pushed the code so far Changed the color scheme for the charts Fixed teammate differentiation across the charts
PitWall Devlog 4 Circuit DNA and Qualifying Analysis What I built Qualifying Analysis get_quali_improvement tracks a driver’s best lap time across Q1, Q2 and Q3 using session.results which returns the results from the three sessions. chart_quali_improvement calculates each driver’s progression between 2 sessions (Q1 and Q2 and so on) get_perfect_lap gets its own chart chart_perfect_lap shows the perfect theoretical lap vs actual best lap where the best lap is the three fastest sectors overall per driver Circuit DNA It classifies a circuit based on its traits (power track, high/low df, high/low drag and so on) get_circuit_dna analyzes the fastest lap telemetry from any session and extracts 6 metrics: full throttle percentage, braking percentage, top speed, average corner speed, low speed corner percentage and high speed cornering percentage. classify_circuit uses those metrics to label a circuit as High Speed, Power Track, High Downforce, Stop/Go or Balanced. Tested across a few circuits as well chart_circuit_dna shows a radar chart overlaying multiple circuits so you can visually compare their personalities get_team_circuit_affinity and get_driver_circuit_affinity calculate average qualifying positions per team and driver based on circuit type Results Silverstone: High Speed — 65% full throttle, 162 km/h avg corner speed Monaco: High Downforce — 34% low speed corners, 27% braking ANT is the strongest qualifier across all circuit types in 2026 Mercedes dominant on Balanced circuits, Ferrari strong on High Speed Problems I hit FastF1 doesn’t support Q1/Q2/Q3 as separate session types so i had to use session.results which has cleaner segment times Circuit classifier kept misclassifying Silverstone as Power Track in the if/elif part of the code Team affinity chart showed each team 3 times in the legend fixed it with dict.fromkeys() to remove the duplicates
PitWall Devlog 5 Weather, Degradation, and Historical Performance What I built Weather Performance get_weather compares average qualifying position for a list of drivers across wet sessions vs. dry sessions and calculates a wet_advantage which is basically just dry avg minus wet avg so a positive number means someone performs better in the rain rather than in the dry. chart_weather visualises it Tire Degradation get_tire_degradation takes each stint and calculates lap-time loss per lap of tyre age. The laps are first filtered so that there are no inaccurate laps and that means excluding laps where there was a red flag, yellow/double yellows, exclude inlaps and outlaps and also if there was a safety car/vsc and also TyreLife > 2 to exclude also the first 2 laps of the stint where in general you have to nurse the tires to warm them up. chart_tire_degradation just visualises it. Teammate Gap get_teammate_gap compares best qualifying times between two teammates across a season. Because not every driver reaches Q3, it falls back Q3 - Q2 - Q1 to find each driver’s actual best time for that quali session. chart_teammate_gap visualises it, red or cyan depending on who was faster. Historical Performance get_fastest_lap_history finds the fastest lap from every quali session since 2018 as that’s how far the data goes. get_driver_circuit_stats does the same thing but for a driver, pulling qualifying position, race position, fastest lap, and finishing result for each year at a given circuit. Sector Times and Pit Stops get_sector_improvement breaks a driver’s sector times down by stint and tyre age, using the same filtering to exclude some laps as the degradation function, get_pitstop_performance calculates stop duration by matching a driver’s pit-in lap to their next pit-out lap, discarding anything under 15s or over 60s since those aren’t really representative. Career Head-to-Head get_h2h_career compares two drivers’ qualifying head-to-head win rate at specific circuits across multiple years, returns a win percentage per location. chart_h2h_career again visualises it. Problems I hit First pass on pit stop duration had no bounds so I was getting stops showing as 3s and 140s which were basically laps flagged as pit laps during safety car periods which is a lot shorter so I added the 15–60s filter also in general I had issues with how tidy the charts looked for example when looking at the stints, each stint is shown with the color of the compound so yellow for medium and so on and for some races which aren’t one stoppers you often use one compound more than once so I lowered the opacity if there is a second stint on the same compound, it’s not a perfect solution but it works
PitWall Devlog 6 - Championship Battle, Overtakes, and Track Evolution What I built Championship Battle Tracker get_championship_battle tracks points for a list of drivers during a season round by round and adds up the points also, tries to load a Sprint session for the same race if it exists it adds those points too, if not it just moves on since most weekends don’t have one. chart_championship_battle is the chart that shows it and it uses the team colors like the other charts and makes the line dashed if there are teammates Overtake Analyzer get_overtakes looks at every position swap between consecutive laps , for each pair of laps it takes everyone’s position and checks every pair of drivers to see if their order flipped, also i had to exclude inlaps and outlaps since when you pit usually you drop many positions get_overtake_summary is just a counter for the overtakes chart_overtakes shows it Track Evolution get_track_evolution looks at how the track itself gets faster as a session goes on, takes every driver’s laps together, sorts them by LapStartTime then tracks a running best lap and an average pace over a window chart_track_evolution visualises it Problems I hit i forgot to exclude inlaps basically the first lap out of the box when you warm the tires for the track_evolution function
PitWall Devlog 7 New functions: DRS Effect Analyzer get_drs_effect checks where drs was used in a lap basically when the rear wing was open (drs zones) and calculates the speed gain within each one, entry speed vs peak Lap Time Delta Chart get_lap_delta compares two drivers’ laps by interpolating both onto the same distance grid using then subtracts one from the other at every point to get a time gap across the lap. Driver & Constructor Standings get_driver_standings and get_constructor_standings basically show the total points accumulated per team and per driver after a certain race A small issue the drs effect function doesn’t work for this year’s races because of the regulation changes and there isn’t exactly drs now but active aero but works for other years
PitWall Devlog 8 Tyre Strategy, and Corner Speeds What I built Tyre Strategy Comparison get_tyre_strategy takes a driver’s laps by stint and shows the used compound (medium, soft, hard, inter and so on) , start lap, end lap, and stint length. chart_tyre_strategy shows it compound by compound and also uses the tyre colors Corner Speed Analysis get_corner_speeds reuses the same logic from mistake detection, but instead of finding the nearest corner to one point, it finds the minimum speed near the apex chart_corner_speeds compares multiple drivers’ apex speed corner by corner for a quali lap also i started working on a fuel load estimator using TyreLife
PitWall Devlog 9 Fuel Load Estimator and Undercut Calculator What I built Fuel Load Effect Estimator get_fuel_effect estimates how much lap time a driver gains from burning off fuel across a race, FastF1 doesn’t have a fuel sensor data, so this is an estimate so it’s not as precise as the actual data chart_fuel_effect compares the estimated fuel effect for a few drivers Undercut/Overcut Effectiveness Calculator get_undercut_effectiveness checks whether pitting earlier than a rival actually gained track position or gave them an advantage, finds when each driver pits, confirms driver1 actually pitted first, measures the time gap between them the lap before driver1 stops, then measures it again a few laps after the rival has also boxed, and the difference between those two numbers tells if the undercut worked although you won’t see this every race actually took me some time to think of an example so that i could test the function and it’s not always effective as you will have older tyres then chart_undercut_effectiveness shows the before/after gap
PitWall Devlog 10 Mini-Sector Dominance and Lap 1 Analysis What I built Mini-Sector Dominance Heatmap get_minisector_dominance splits a lap and figures out which driver had the highest average speed in each one chart_minisector_dominance shows it Lap 1 Analysis get_lap1_analysis compares grid position to position at the end of lap 1 to show how many places a driver gained after the start and the first lap as a whole basically chart_lap1_analysis shows it Anyway this is from the Hungarian gp which was last week:
PitWall Devlog 12 Rivalry Report, Circuit Evolution and Reliability Tracker What I built Rivalry Report Card get_rivalry_report combines session pace, consistency , and career h2h across circuits and years and puts it all together, chart_rivalry_report shows the two side by side using make_subplots Multi-Year Circuit Evolution get_circuit_evolution loops get_circuit_dna for a range of years for one circuit and then tracks how top speed and average corner speed change over time although when testing it you might see a spike somewhere which probably means that it was affected by rain Reliability/DNF Tracker get_reliability_tracker takes a season and tallies each driver’s finishing status per race into finishes, DNFs, and other non-finishes (DNS/DSQ or NC) Problems I hit Forgot to fix the lap filtering properly and it did ruin the consistency in the rivalry report function because it was a lap affected by traffic...
|
1793857864.3680186
|
1794721864.3680186
|
|
19175
|
ClimateBox by @Ved | Stardance
|
Ved
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: ClimateBox by @Ved | Stardance
|
1793494394.0705554
|
1794099194.0705554
|
|
19176
|
My very own WebOS by @Shivank_gy | Stardance
|
Shivank_gy
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @Shivank_gy | Stardanc Title: My very own WebOS by @Shivank_gy | Stardance...
|
1793512085.2055354
|
1794116885.2055354
|
|
19177
|
see of disaster by @yayabskt | Stardance
|
yayabskt
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: see of disaster by @yayabskt | Stardance
|
1793476315.7561705
|
1794081115.7561705
|
|
19178
|
Aera Studia by @timotheyknezi | Stardance
|
timotheyknezi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Aera Studia by @timotheyknezi | Stardance
|
1793339426.1116369
|
1793944226.1116369
|
|
19179
|
Cyberpunk Mantis arm prop by @zclayton2010 | Stard Cyberpunk Mantis arm prop by @zclayton2010 | Stardance...
|
zclayton2010
|
0
|
0.25
|
0
|
[]
|
[{"post_id": 10915, "ts": "202 [{"post_id": 10915, "ts": "2026-06-17T21:49:32Z", "hours": 0.2544, "text": "The CAD (onshape) and the Arduino code"}]...
|
Title: Cyberpunk Mantis arm prop by @zclayton2010 Title: Cyberpunk Mantis arm prop by @zclayton2010 | Stardance
Devlogs:
The CAD (onshape) and the Arduino code...
|
1793872130.966658
|
1794476930.966658
|
|
19180
|
My awesome macropad! by @saikarthik | Stardance
|
saikarthik
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @saikarthik | Stard Title: My awesome macropad! by @saikarthik | Stardance...
|
1793425664.8444884
|
1794030464.8444884
|
|
19181
|
Untitled by @saikarthik | Stardance
|
saikarthik
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled by @saikarthik | Stardance
|
1793926343.8348436
|
1794531143.8348436
|
|
19182
|
argus mission by @diyab | Stardance
|
diyab
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: argus mission by @diyab | Stardance
|
1793814806.9109218
|
1794419606.9109218
|
|
19183
|
quick-claude by @andrewh | Stardance
|
andrewh
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: quick-claude by @andrewh | Stardance
|
1793879253.981015
|
1794484053.981015
|
|
19184
|
My very own WebOS by @andrewh | Stardance
|
andrewh
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @andrewh | Stardance
|
1793530250.3189578
|
1794135050.3189578
|
|
19185
|
Frictionless by @ritvij_sharma10 | Stardance
|
ritvij_sharma10
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @ritvij_sharma10 | Stardanc Title: Frictionless by @ritvij_sharma10 | Stardance...
|
1793440229.9536428
|
1794045029.9536428
|
|
19186
|
foodsavr by @itis | Stardance
|
itis
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: foodsavr by @itis | Stardance
|
1793335684.444849
|
1793940484.444849
|
|
19187
|
database in go by @andrewh | Stardance
|
andrewh
|
0
|
0.29
|
0
|
[]
|
[{"post_id": 9240, "ts": "2026 [{"post_id": 9240, "ts": "2026-06-15T14:51:00Z", "hours": 0.2875, "text": "terminal user interface i implemented the feature where users can open a log file with the database instructions. The tui uses the bubble tea framework so I just wired in the list component from bubbles."}]...
|
Title: database in go by @andrewh | Stardance
Dev Title: database in go by @andrewh | Stardance
Devlogs:
terminal user interface i implemented the feature where users can open a log file with the database instructions. The tui uses the bubble tea framework so I just wired in the list component from bubbles....
|
1794016143.7381537
|
1794620943.7381537
|
|
19188
|
My first slack bot! by @Vermillion | Stardance
|
Vermillion
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @Vermillion | Starda Title: My first slack bot! by @Vermillion | Stardance...
|
1793911918.2244368
|
1794516718.2244368
|
|
19189
|
Untitled by @laurengracebroadbent | Stardance
|
laurengracebroadbent
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled by @laurengracebroadbent | Stardan Title: Untitled by @laurengracebroadbent | Stardance...
|
1793778619.050998
|
1794642619.050998
|
|
19190
|
Astroview by @Valerio | Stardance
|
Valerio
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Astroview by @Valerio | Stardance
|
1793569888.4156945
|
1794174688.4156945
|
|
19191
|
My awesome macropad! by @sagarmza09 | Stardance
|
sagarmza09
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @sagarmza09 | Stard Title: My awesome macropad! by @sagarmza09 | Stardance...
|
1794041508.812755
|
1794646308.812755
|
|
19192
|
Battlebot for the 150g antweight category by @maty Battlebot for the 150g antweight category by @matysunka | Stardance...
|
matysunka
|
0
|
18.26
|
0
|
[]
|
[{"post_id": 40837, "ts": "202 [{"post_id": 40837, "ts": "2026-08-04T16:52:51Z", "hours": 9.195, "text": "Looking Ahead After the tournament I realized that shufflers have a huge advantage. Because they get a 50% weight bonus , they can have bigger weapons, stronger armor, and even when another robot hits you, being 75 grams heavier is a big advantage. I successfully built my first working shuffler prototype, and after seeing how well it worked, I decided this is what I want to focus on for my next robots."}, {"post_id": 31358, "ts": "2026-07-19T18:01:05Z", "hours": 9.0625, "text": "Development Log – First Tournament Finalizing the Robots Before the first tournament I finally finished both of my battlebots. Nailee Nailee is a simple pusher with a TPU chassis and PLA-ST forks. I wanted it to be as simple and reliable as possible, without any active weapon. Tongueboy Tongueboy is built in almost the same way as Nailee, but it has an extra servo connected to a flipper arm so it can try to grab or flip opponents. Wheel Development The wheels ended up taking way more time than I expected. Version 1 The first idea was just a 3D printed cylinder with silicone poured around it to make a tire. It sounded like a good idea, but it didn’t work at all. The silicone I have is really soft, so it just spun around the hub instead of driving the robot. Version 2 For the second version I added ridges to the hub so the silicone couldn’t slip while driving forwards or backwards. That fixed one problem, but the tire could still move sideways if it got hit. Version 3 So for the final version I added ridges around the sides as well to lock the silicone in every direction. This made the wheels heavier than I wanted, but since neither robot has a spinner weapon I could afford the extra weight. In the end I casted 8 wheels for both robots and some spares, and honestly I’m really happy with how they turned out. At the tournament they had great grip and worked exactly how I hoped. First Tournament Both robots competed in their first tournament against 22 other robots. Results: Nailee: 10th place Tongueboy: 8th place For my second competition I was really happy with those results. Nailee Nailee did pretty well until it fought a hammer saw. The very first hit landed right above the electronics and instantly killed the expensive Malenki Nano, so that was the end of the match. It definitely showed me that I need to spend more time protecting the electronics instead of just making everything lightweight. Tongueboy When Tongueboy had to fight the same hammer saw, I didn’t want the same thing to happen again. I took a piece of chassis from another damaged robot and used it as extra armor over the Malenki Nano. Surprisingly, it actually worked. The electronics survived the whole fight. The fight itself… not so much. 😅 It was completely one-sided and Tongueboy got absolutely beaten up. It still survived, but it definitely looked a lot worse afterwards. What I Learned Even though both robots took a lot of damage, I learned a ton from this tournament. The current wheel design works really well, so I’ll definitely keep using it. The Malenki Nano needs much better protection. Every fight gives me new ideas for improvements. Overall I’m really happy with how both robots performed. They weren’t perfect, but finishing 8th and 10th out of 22 robots on their first competition gave me a great starting point for the next versions."}]...
|
Title: Battlebot for the 150g antweight category b Title: Battlebot for the 150g antweight category by @matysunka | Stardance
Devlogs:
Development Log – First Tournament Finalizing the Robots Before the first tournament I finally finished both of my battlebots. Nailee Nailee is a simple pusher with a TPU chassis and PLA-ST forks. I wanted it to be as simple and reliable as possible, without any active weapon. Tongueboy Tongueboy is built in almost the same way as Nailee, but it has an extra servo connected to a flipper arm so it can try to grab or flip opponents. Wheel Development The wheels ended up taking way more time than I expected. Version 1 The first idea was just a 3D printed cylinder with silicone poured around it to make a tire. It sounded like a good idea, but it didn’t work at all. The silicone I have is really soft, so it just spun around the hub instead of driving the robot. Version 2 For the second version I added ridges to the hub so the silicone couldn’t slip while driving forwards or backwards. That fixed one problem, but the tire could still move sideways if it got hit. Version 3 So for the final version I added ridges around the sides as well to lock the silicone in every direction. This made the wheels heavier than I wanted, but since neither robot has a spinner weapon I could afford the extra weight. In the end I casted 8 wheels for both robots and some spares, and honestly I’m really happy with how they turned out. At the tournament they had great grip and worked exactly how I hoped. First Tournament Both robots competed in their first tournament against 22 other robots. Results: Nailee: 10th place Tongueboy: 8th place For my second competition I was really happy with those results. Nailee Nailee did pretty well until it fought a hammer saw. The very first hit landed right above the electronics and instantly killed the expensive Malenki Nano, so that was the end of the match. It definitely showed me that I need to spend more time protecting the electronics instead of just making everything lightweight. Tongueboy When Tongueboy had to fight the same hammer saw, I didn’t want the same thing to happen again. I took a piece of chassis from another damaged robot and used it as extra armor over the Malenki Nano. Surprisingly, it actually worked. The electronics survived the whole fight. The fight itself… not so much. 😅 It was completely one-sided and Tongueboy got absolutely beaten up. It still survived, but it definitely looked a lot worse afterwards. What I Learned Even though both robots took a lot of damage, I learned a ton from this tournament. The current wheel design works really well, so I’ll definitely keep using it. The Malenki Nano needs much better protection. Every fight gives me new ideas for improvements. Overall I’m really happy with how both robots performed. They weren’t perfect, but finishing 8th and 10th out of 22 robots on their first competition gave me a great starting point for the next versions.
Looking Ahead After the tournament I realized that shufflers have a huge advantage. Because they get a 50% weight bonus , they can have bigger weapons, stronger armor, and even when another robot hits you, being 75 grams heavier is a big advantage. I successfully built my first working shuffler prototype, and after seeing how well it worked, I decided this is what I want to focus on for my next robots....
|
1793530152.1826777
|
1794134952.1826777
|
|
19193
|
My awesome macropad! by @RagtagSphere969 | Stardan My awesome macropad! by @RagtagSphere969 | Stardance...
|
RagtagSphere969
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @RagtagSphere969 | Title: My awesome macropad! by @RagtagSphere969 | Stardance...
|
1793335867.2727244
|
1793940667.2727244
|
|
19194
|
My first slack bot! by @Jace | Stardance
|
Jace
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @Jace | Stardance
|
1793425771.1916933
|
1794030571.1916933
|
|
19195
|
My awesome macropad! by @nishanth05 | Stardance
|
nishanth05
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @nishanth05 | Stard Title: My awesome macropad! by @nishanth05 | Stardance...
|
1793486931.6443908
|
1794091731.6443908
|
|
19196
|
My awesome macropad! by @nishanth05 | Stardance
|
nishanth05
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @nishanth05 | Stard Title: My awesome macropad! by @nishanth05 | Stardance...
|
1793487113.8825433
|
1794091913.8825433
|
|
19197
|
SniperPad by @nishanth05 | Stardance
|
nishanth05
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: SniperPad by @nishanth05 | Stardance
|
1794041644.686547
|
1794646444.686547
|
|
19198
|
My awesome macropad! by @rhenisam2008 | Stardance
|
rhenisam2008
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @rhenisam2008 | Sta Title: My awesome macropad! by @rhenisam2008 | Stardance...
|
1793361090.196091
|
1793965890.196091
|
|
19199
|
tdo - Task Manager CLI by @aadi_da_noob | Stardanc tdo - Task Manager CLI by @aadi_da_noob | Stardance...
|
aadi_da_noob
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: tdo - Task Manager CLI by @aadi_da_noob | S Title: tdo - Task Manager CLI by @aadi_da_noob | Stardance...
|
1793307352.6637921
|
1793912152.6637921
|
|
19200
|
My awesome macropad! by @bronzeEagle | Stardance
|
bronzeEagle
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @bronzeEagle | Star Title: My awesome macropad! by @bronzeEagle | Stardance...
|
1793411373.1498168
|
1794016173.1498168
|