|
11495
|
My first slack bot! by @xewis27806 | Stardance
|
xewis27806
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @xewis27806 | Starda Title: My first slack bot! by @xewis27806 | Stardance...
|
1792655436.1365502
|
1793260236.1365502
|
|
67114
|
soul knight by @xev123_ | Stardance
|
xev123_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: soul knight by @xev123_ | Stardance
|
1793105689.4074612
|
1793710489.4074612
|
|
58220
|
My awesome macropad! by @xev | Stardance
|
xev
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xev | Stardance
|
1792741930.111631
|
1793346730.111631
|
|
62374
|
My Portfolio ig :D by @xev | Stardance
|
xev
|
1
|
1.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-17T07:11:03Z", "hours": 1.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "So i made my own website telling how am i and tbh the thing that was challenging was building my little kiwi bot yeah i love kiwi so as its just a website about nothing really to test about tbh :D", "repo": "https://github.com/itzkimzu/My-Website-ig", "demo": "https://mywebsite3334.netlify.app/"}]...
|
[{"post_id": 69512, "ts": "202 [{"post_id": 69512, "ts": "2026-09-17T06:56:05Z", "hours": 1.1317, "text": "My Own Portfolio YAY!!"}]...
|
Title: My Portfolio ig :D by @xev | Stardance
Dev Title: My Portfolio ig :D by @xev | Stardance
Devlogs:
My Own Portfolio YAY!!
Ships:
So i made my own website telling how am i and tbh the thing that was challenging was building my little kiwi bot yeah i love kiwi so as its just a website about nothing really to test about tbh :D...
|
1793209987.35141
|
1793296387.35141
|
|
23566
|
Shortcut Macropad by @xeterii | Stardance
|
xeterii
|
0
|
0.63
|
0
|
[]
|
[{"post_id": 18512, "ts": "202 [{"post_id": 18512, "ts": "2026-06-29T18:04:55Z", "hours": 0.6328, "text": "This is my first devlog ever! I followed the guide for building my PCB for the MacroPad but I didn´t track my time. So in this session I started to design the MacroPad´s case: I struggled a lot using Fusion but I managed to use the core feature. Next time I will continue designing the first version of the case and learn more about how to use Fusion."}]...
|
Title: Shortcut Macropad by @xeterii | Stardance
Title: Shortcut Macropad by @xeterii | Stardance
Devlogs:
This is my first devlog ever! I followed the guide for building my PCB for the MacroPad but I didn´t track my time. So in this session I started to design the MacroPad´s case: I struggled a lot using Fusion but I managed to use the core feature. Next time I will continue designing the first version of the case and learn more about how to use Fusion....
|
1792706053.3715615
|
1793310853.3715615
|
|
62098
|
My awesome macropad! by @xer | Stardance
|
xer
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xer | Stardance
|
1793044196.717878
|
1793648996.717878
|
|
19509
|
Keyboard to Controller Input for xCloud Gaming by Keyboard to Controller Input for xCloud Gaming by @xeon12832 | Stardance...
|
xeon12832
|
1
|
4.0
|
46
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-17T01:06:04Z", "hours": 4.0, "multiplier": 11.22, "payout": 46, "blessing": "neutral", "text": "I have built a tool that converts keyboard inputs into controller inputs for browser based games and Xbox Cloud Gaming. This project was a rewarding challenge, particularly when navigating the challenge of connecting my macOS app to the web. I eventually developed a solution using a JavaScript bridge via localhost to enable seamless communication. Overall, it was a great experience, and I am excited to share this tool with others who want to play browser games without a physical controller. I hope to inspire others to make tools which will help their own lives.", "repo": "https://github.com/xeon12832/CloudControllerFinal", "demo": "https://github.com/xeon12832/CloudControllerFinal/releases/tag/v1"}]...
|
[{"post_id": 10340, "ts": "202 [{"post_id": 10340, "ts": "2026-06-17T00:44:11Z", "hours": 0.2736, "text": "Log 8 (16 Mins) I have fully finished the app. For the final touches, I added more detailed instructions and made things more intuitive. I have started to import the project into my GitHub repo. I will also hope to ship sometime today. Overall, I added all the features I wanted to make, and I hope to inspire others to make similar tools. Always remember to make tools that would improve your daily life."}, {"post_id": 10325, "ts": "2026-06-17T00:06:42Z", "hours": 0.4953, "text": "Log 7 (29 mins): I have completed the controller input integration by adding a d-pad mapper. Additionally, I’ve introduced a custom theme maker that allows users to use a color picker to customize base and accent colors. I plan to move the theme editor button to the top for better accessibility. I am currently applying final touches and improvements, and I look forward to shipping the project soon!"}, {"post_id": 10205, "ts": "2026-06-16T20:31:35Z", "hours": 0.525, "text": "Log 6 (29 Mins): I’ve implemented a visual controller diagram to improve the user interface. My current progress has slowed slightly due to some GitHub synchronization issues, so I am prioritizing fixing those repository access errors before moving forward with further feature development. If anyone has suggestions or can help with the GitHub issues, please let me know. Thank you"}, {"post_id": 10137, "ts": "2026-06-16T18:58:31Z", "hours": 0.3658, "text": "Log 5 (21 mins): I’ve implemented a setup button with clear configuration instructions and added a selection of default themes. Moving forward, I plan to expand the customization options for themes while focusing on refining the overall app performance and user experience."}, {"post_id": 10113, "ts": "2026-06-16T18:21:51Z", "hours": 0.9419, "text": "Log 4 (56 Mins): Finally added a remaper tool. Any key can be mapped to any controller input. Have to add d-pad later. Also have to add themes. Might also add a controller diagram. But thats all for now."}, {"post_id": 10027, "ts": "2026-06-16T16:19:24Z", "hours": 0.6414, "text": "Log 3 (22 Mins): I’m focusing on integrating my macOS app with the Chrome DevTools script for a more seamless connection. My roadmap includes developing a Chrome extension to automate the configuration of the JavaScript code for users. Additionally, I’m planning to enhance the UI with custom themes, including various color schemes and design options. In the future possibly even custom designs."}, {"post_id": 9961, "ts": "2026-06-16T14:22:45Z", "hours": 0.6475, "text": "Log 2 (38 Mins): I hit a few roadblocks with the driver integration, which proved to be quite challenging to get working correctly. To keep moving forward, I changed my goal a bit and successfully developed a Java script that functions within Chrome DevTools. While this works for now, my long term goal remains to refine the SwiftUI application so that the controller inputs can eventually work systemwide. I will add more games and an ability to configure controls eventually."}, {"post_id": 9916, "ts": "2026-06-16T12:57:19Z", "hours": 0.5017, "text": "Log 1 (30 Mins) I have made an app using SwiftUI that is able to detect keyboard presses. I made it so that when I press a key it shows it on screen. I also used drivers by tekezo on Github. This allowed me to record my keystrokes. My next step would be to convert those presses into controler inputs. I am planning to use Forza Horizon 6 as my test game. I will also add a feature where users can change each key to a different input on the virtual controller."}]...
|
Title: Keyboard to Controller Input for xCloud Gam Title: Keyboard to Controller Input for xCloud Gaming by @xeon12832 | Stardance
Devlogs:
Log 1 (30 Mins) I have made an app using SwiftUI that is able to detect keyboard presses. I made it so that when I press a key it shows it on screen. I also used drivers by tekezo on Github. This allowed me to record my keystrokes. My next step would be to convert those presses into controler inputs. I am planning to use Forza Horizon 6 as my test game. I will also add a feature where users can change each key to a different input on the virtual controller.
Log 2 (38 Mins): I hit a few roadblocks with the driver integration, which proved to be quite challenging to get working correctly. To keep moving forward, I changed my goal a bit and successfully developed a Java script that functions within Chrome DevTools. While this works for now, my long term goal remains to refine the SwiftUI application so that the controller inputs can eventually work systemwide. I will add more games and an ability to configure controls eventually.
Log 3 (22 Mins): I’m focusing on integrating my macOS app with the Chrome DevTools script for a more seamless connection. My roadmap includes developing a Chrome extension to automate the configuration of the JavaScript code for users. Additionally, I’m planning to enhance the UI with custom themes, including various color schemes and design options. In the future possibly even custom designs.
Log 4 (56 Mins): Finally added a remaper tool. Any key can be mapped to any controller input. Have to add d-pad later. Also have to add themes. Might also add a controller diagram. But thats all for now.
Log 5 (21 mins): I’ve implemented a setup button with clear configuration instructions and added a selection of default themes. Moving forward, I plan to expand the customization options for themes while focusing on refining the overall app performance and user experience.
Log 6 (29 Mins): I’ve implemented a visual controller diagram to improve the user interface. My current progress has slowed slightly due to some GitHub synchronization issues, so I am prioritizing fixing those repository access errors before moving forward with further feature development. If anyone has suggestions or can help with the GitHub issues, please let me know. Thank you
Log 7 (29 mins): I have completed the controller input integration by adding a d-pad mapper. Additionally, I’ve introduced a custom theme maker that allows users to use a color picker to customize base and accent colors. I plan to move the theme editor button to the top for better accessibility. I am currently applying final touches and improvements, and I look forward to shipping the project soon!
Log 8 (16 Mins) I have fully finished the app. For the final touches, I added more detailed instructions and made things more intuitive. I have started to import the project into my GitHub repo. I will also hope to ship sometime today. Overall, I added all the features I wanted to make, and I hope to inspire others to make similar tools. Always remember to make tools that would improve your daily life.
Ships:
I have built a tool that converts keyboard inputs into controller inputs for browser based games and Xbox Cloud Gaming. This project was a rewarding challenge, particularly when navigating the challenge of connecting my macOS app to the web. I eventually developed a solution using a JavaScript bridge via localhost to enable seamless communication. Overall, it was a great experience, and I am excited to share this tool with others who want to play browser games without a physical controller. I hope to inspire others to make tools which will help their own lives....
|
1793245986.8640676
|
1793332386.8640676
|
|
19887
|
DynamicWeather by @xeon12832 | Stardance
|
xeon12832
|
0
|
3.29
|
0
|
[]
|
[{"post_id": 27873, "ts": "202 [{"post_id": 27873, "ts": "2026-07-13T19:34:58Z", "hours": 3.2911, "text": "I made a weather app called DynamicWeather, for ios, Macos, and iPados. It has live weather tracking and live activities in the menu bar on mac, or on the lockscreen and dynamic island on iPhone and iPad. I also added a dev settings page with a hidden password for me to test and debug the app. I used the OpenWeather API and the National Weather Service API for my weather information."}]...
|
Title: DynamicWeather by @xeon12832 | Stardance
D Title: DynamicWeather by @xeon12832 | Stardance
Devlogs:
I made a weather app called DynamicWeather, for ios, Macos, and iPados. It has live weather tracking and live activities in the menu bar on mac, or on the lockscreen and dynamic island on iPhone and iPad. I also added a dev settings page with a hidden password for me to test and debug the app. I used the OpenWeather API and the National Weather Service API for my weather information....
|
1792806664.9093292
|
1793411464.9093292
|
|
24301
|
volume mixer by @xeon | Stardance
|
xeon
|
0
|
4.37
|
0
|
[]
|
[{"post_id": 26693, "ts": "202 [{"post_id": 26693, "ts": "2026-07-11T17:09:36Z", "hours": 0.6378, "text": "volume mixer actually works!!"}, {"post_id": 17948, "ts": "2026-06-28T22:10:43Z", "hours": 1.7772, "text": "just finished writing the circuitpython code for the raspberry pi pico side of the mixer. it reads 4 rotary encoders and sends commands over usb serial to the pc controller i made earlier.basically how it works:each knob has a data pin, clock pin, and a button pinturning the knob sends stuff like “SPOTIFY_UP” or “DISCORD_DOWN” over usbpressing the knob down sends “SPOTIFY_MUTE” etcdial 4 is still tbd because i havent decided what i want it to do yeti havent tested it on real hardware yet since im still waiting on parts, but the logic should work. the hardest part was figuring out how rotary encoders actually send their signals"}, {"post_id": 16431, "ts": "2026-06-26T18:53:10Z", "hours": 1.9539, "text": "finally got the volume control working!! my python script works basically it can control: spotify volume discord volume my whole pc volume and if i press the knob (once i actually build it) it’ll mute each one the system volume part was a pain - pycaw kept giving me errors so i just used powershell to simulate pressing the volume keys instead. sometimes the easy way is better ig"}]...
|
Title: volume mixer by @xeon | Stardance
Devlogs: Title: volume mixer by @xeon | Stardance
Devlogs:
finally got the volume control working!! my python script works basically it can control: spotify volume discord volume my whole pc volume and if i press the knob (once i actually build it) it’ll mute each one the system volume part was a pain - pycaw kept giving me errors so i just used powershell to simulate pressing the volume keys instead. sometimes the easy way is better ig
just finished writing the circuitpython code for the raspberry pi pico side of the mixer. it reads 4 rotary encoders and sends commands over usb serial to the pc controller i made earlier.basically how it works:each knob has a data pin, clock pin, and a button pinturning the knob sends stuff like “SPOTIFY_UP” or “DISCORD_DOWN” over usbpressing the knob down sends “SPOTIFY_MUTE” etcdial 4 is still tbd because i havent decided what i want it to do yeti havent tested it on real hardware yet since im still waiting on parts, but the logic should work. the hardest part was figuring out how rotary encoders actually send their signals
volume mixer actually works!!...
|
1793260434.3091953
|
1793865234.3091953
|
|
43257
|
Deltarune Voiceline Portal by @xeo | Stardance
|
xeo
|
0
|
3.74
|
0
|
[]
|
[{"post_id": 54277, "ts": "202 [{"post_id": 54277, "ts": "2026-08-25T06:00:20Z", "hours": 3.7356, "text": "DVP (Ver. 0.1) I’ve implemented the file upload system using Cloudflare R2! (Took forever to find a guide that actually worked 😭 ) I’ve designed the basic front end and styled it, though I’d like to make it a bit fancier given it’s very simple right now, just some text using the Deltarune font. In the future I’d like to code the accounts and the ability assign specific lines to certain individuals! [I started this off Stardance, hence the lack of dev logs]"}]...
|
Title: Deltarune Voiceline Portal by @xeo | Starda Title: Deltarune Voiceline Portal by @xeo | Stardance
Devlogs:
DVP (Ver. 0.1) I’ve implemented the file upload system using Cloudflare R2! (Took forever to find a guide that actually worked 😭 ) I’ve designed the basic front end and styled it, though I’d like to make it a bit fancier given it’s very simple right now, just some text using the Deltarune font. In the future I’d like to code the accounts and the ability assign specific lines to certain individuals! [I started this off Stardance, hence the lack of dev logs]...
|
1793213339.1790488
|
1793818139.1790488
|
|
53182
|
Better Bedrock Menus by @xeo | Stardance
|
xeo
|
0
|
5.36
|
0
|
[]
|
[{"post_id": 81954, "ts": "202 [{"post_id": 81954, "ts": "2026-10-23T05:12:21Z", "hours": 0.7397, "text": "BBM 0.6.1 I made update checking async! I also added a little message in the info command that states the latest version so one could easily compare between the two. The rest of the time was me trying to figure out how to package Bstats in with Maven, to little avail"}, {"post_id": 74238, "ts": "2026-09-27T00:58:18Z", "hours": 2.1269, "text": "Async timeeeee! (0.6.1-dev) I’m currently working on re-coding the reading and writing of JSON files in Better Bedrock Menus to be async! Reading and writing files should really always be done asynchronously, so, despite the pretty small impact to actual performance, this is good practice (I think)!"}, {"post_id": 53401, "ts": "2026-08-23T22:50:53Z", "hours": 1.1986, "text": "(BBM Ver. 0.6.0) I added support for sending menus through Skript which allows for people to easily integrate bedrock menus with their pre-existing code!"}, {"post_id": 53211, "ts": "2026-08-23T17:31:40Z", "hours": 1.295, "text": "BBM (Ver. 0.5.5) I stylized the usage messages and added a permission check for self-menus! *I know it was a lot of time for how small the change was, but I spent some time cleaning up code and re-familiarizing myself with the codebase. *"}]...
|
Title: Better Bedrock Menus by @xeo | Stardance
D Title: Better Bedrock Menus by @xeo | Stardance
Devlogs:
BBM (Ver. 0.5.5) I stylized the usage messages and added a permission check for self-menus! *I know it was a lot of time for how small the change was, but I spent some time cleaning up code and re-familiarizing myself with the codebase. *
(BBM Ver. 0.6.0) I added support for sending menus through Skript which allows for people to easily integrate bedrock menus with their pre-existing code!
Async timeeeee! (0.6.1-dev) I’m currently working on re-coding the reading and writing of JSON files in Better Bedrock Menus to be async! Reading and writing files should really always be done asynchronously, so, despite the pretty small impact to actual performance, this is good practice (I think)!
BBM 0.6.1 I made update checking async! I also added a little message in the info command that states the latest version so one could easily compare between the two. The rest of the time was me trying to figure out how to package Bstats in with Maven, to little avail...
|
1792738409.5113766
|
1793343209.5113766
|
|
66160
|
Best Alarm Clock by @xeo | Stardance
|
xeo
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Best Alarm Clock by @xeo | Stardance
|
1793094772.3179505
|
1793699572.3179505
|
|
66161
|
Fast-Key by @xeo | Stardance
|
xeo
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Fast-Key by @xeo | Stardance
|
1793094775.7518427
|
1793699575.7518427
|
|
67110
|
Blog by @xeo | Stardance
|
xeo
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Blog by @xeo | Stardance
|
1793105687.3986924
|
1793710487.3986924
|
|
44255
|
My awesome macropad! by @xenonite_ | Stardance
|
xenonite_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xenonite_ | Starda Title: My awesome macropad! by @xenonite_ | Stardance...
|
1792579888.2542374
|
1793184688.2542374
|
|
44268
|
My Personal Website by @xenonite_ | Stardance
|
xenonite_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My Personal Website by @xenonite_ | Stardan Title: My Personal Website by @xenonite_ | Stardance...
|
1792579894.2269893
|
1793184694.2269893
|
|
46549
|
webOS for my dad's birthday by @xenonite_ | St webOS for my dad's birthday by @xenonite_ | Stardance...
|
xenonite_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: webOS for my dad's birthday by @xenonit Title: webOS for my dad's birthday by @xenonite_ | Stardance...
|
1792669720.9865377
|
1793274520.9865377
|
|
19937
|
My very own WebOS by @xenon_is_gas | Stardance
|
xenon_is_gas
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @xenon_is_gas | Starda Title: My very own WebOS by @xenon_is_gas | Stardance...
|
1792741848.964066
|
1793346648.964066
|
|
21042
|
Vibe-Atmospheric Productivity by @xenon_is_gas | S Vibe-Atmospheric Productivity by @xenon_is_gas | Stardance...
|
xenon_is_gas
|
0
|
1.76
|
0
|
[]
|
[{"post_id": 11847, "ts": "202 [{"post_id": 11847, "ts": "2026-06-19T08:43:30Z", "hours": 0.4936, "text": "The github page is finally online and updated with proper requirements.Working on the fix as to why the modules fire in wrong order leading to a crash."}, {"post_id": 11337, "ts": "2026-06-18T15:25:55Z", "hours": 1.2681, "text": "First log dont really have much to say except the modules have a mind of their own so working on fixing that currently and also improving the ui to look more pleasing and presentable"}]...
|
Title: Vibe-Atmospheric Productivity by @xenon_is_ Title: Vibe-Atmospheric Productivity by @xenon_is_gas | Stardance
Devlogs:
First log dont really have much to say except the modules have a mind of their own so working on fixing that currently and also improving the ui to look more pleasing and presentable
The github page is finally online and updated with proper requirements.Working on the fix as to why the modules fire in wrong order leading to a crash....
|
1792799386.6277325
|
1793404186.6277325
|
|
66761
|
Openport by @xenoaitham | Stardance
|
xenoaitham
|
1
|
47.0
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-10T20:37:25Z", "hours": 47.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made OpenPorts, an attack surface monitor for small companies: you add a domain, prove you own it by publishing one TXT record at _openports.<yourdomain> , and a scanner that lives inside the web app itself sweeps the 100 most common TCP ports, has one short conversation with every open port, reads the TLS certificate on 443 and the mail ports, and checks SPF, DMARC, MX, HSTS, the http to https redirect and the server header. Every scan is diffed against the previous one, changes are held unconfirmed until a second scan agrees, and verified targets are rescanned every six hours without anyone pressing anything. The whole product is one process and one SQLite file: no redis, no docker, no queue service, two commands to run. The hardest bug was one I inflicted on myself. The scheduler’s due query used ORM column objects inside a raw SQL fragment, the ORM rendered them unqualified, and inside a correlated subquery a bare id resolved to the wrong table, so the query compared every scan against itself and concluded the target was due on every two second tick. The worker scanned the demo host seventeen times in three minutes before I noticed. The fix was hand qualifying the table names and pinning the generated SQL in tests, so the next person who makes that mistake fails a test instead of discovering it from a host’s point of view. The second hard part was honesty under a flapping network: the demo host’s port 80 gives different answers to different conversations seconds apart, so a naive monitor would cry wolf on every run. Changes now announce immediately, tagged unconfirmed, and only confirm when two of the last three scans agree. I am proud that nothing on screen is faked. Findings are never staged; every number in the report came off the wire, including the disagreements, which the report prints instead of hiding. And I am proud of the gate: nothing is ever scanned until ownership is proven, the worker rechecks verification before touching the network, and the single exception is scanme.nmap.org, which the Nmap project runs for exactly this purpose. To test: open https://emotions-finger-earthquake-hints.trycloudflare.com in a browser, nothing to install. Click run scan again on the target and watch a real scan finish in about four seconds, then expand raw scan output to see what actually came off the wire. Or run it locally: npm install, npm run dev, then open http://localhost:4310.", "repo": "https://github.com/xenoaitham/openports", "demo": "https://openports-live-xenoaitham.web.app/"}]...
|
[{"post_id": 78451, "ts": "202 [{"post_id": 78451, "ts": "2026-10-10T20:30:44Z", "hours": 3.3769, "text": "022: v1.0 stamped, the gap priced a fourteenth time One headline: stamp v1.0. Not new scope, just a clean stamp on what already works, so a stranger can clone, install, run, add a domain, publish one TXT record, and get real reports every six hours. The owner added one rule above everything else: commit nothing and push nothing until they say the word, so every git step is prepared and held. The box rebooted again, the fifth pickup like it, and both handoff processes died with it. Restoring them took one command each. The database wasn’t empty this time, since the owner had seeded two scans, and that led to the best surprise: the seed had made the target six hours stale, so on boot the scheduler enqueued a scan by itself. First scheduled rescan on the real clock since the cadence was proven, no rewind, no hand-inserted row, no request in the log before it. Four independent sightings of the due branch now. The scratch got cleared: four places, thirteen lines, all dead comments, a duplicate export and an unused constant, with the test count at 56 before and after. The README got read as a stranger would read it, every claim checked against the code, and none lied. One omission fixed: a single line naming the Node version. The domain question got priced again, and the baseline held on every corner. The cloud CLI lists thirteen projects, and every one answered that the DNS API is disabled. Enabling it and creating a zone is a billable action nobody takes on their own behalf, so two targets on one cadence and two scans at once stay pinned by a race test instead of watched live. A fresh set of twelve screenshots came out clean, though the browser cache was gone again and had to be refetched. The changes feed still has never shown a populated state on live data: seven done scans, every diff empty, nothing staged to force one. The release steps are queued in order, waiting for the word: scratch commit, README commit, version stamp, tag, push, release."}, {"post_id": 78295, "ts": "2026-10-10T10:14:48Z", "hours": 7.8275, "text": "007: the cadence on the real clock, and the gap that stands The oldest open question in the project closed: the six hour cadence fired on the real clock, no rewind, nothing inserted by hand. The scheduled scan appeared about a second after the mark, got claimed seven milliseconds later, finished in under four seconds, and stored the same empty diff as the one before it. Both feeds stayed honestly quiet. Every process watching it had died and the machine had been rebuilt around them, which didn’t matter, since the clock reads the database, not any process. One small decision along the way: the politeness check stays on one stored address per target. Matching every address would need an address history table inside the claim, real machinery for round-robin hosts a small company rarely has, and politeness is a courtesy, not a correctness property. Two lessons for the watching kit. Wiping the database with rm deafens any watcher, since it keeps polling the deleted file and the log just stops with no error, so restart it after every wipe, and after the migrate. And the production server doesn’t migrate, only dev does. The gap that stands: two owned targets sharing the cadence, and two scans running at once, still pinned by a race test instead of watched live. Two more runs checked, and the second went deeper. No DNS credentials anywhere, then a cloud CLI turned up with two accounts, one with a dead token and one that sees ten projects with the DNS service disabled on every one. There’s a difference between no panel and a panel one billable step away, and enabling it is a purchase on someone’s account, not something to do unprompted. Meanwhile the loop held every time: add the public test target, scan it, same four findings, port 80 splitting its personality between a 200 on the banner grab and a refused connection on the redirect check. It never flapped, so the populated changes feed has still never been seen on live data, and nothing was staged to force it."}, {"post_id": 78014, "ts": "2026-10-09T06:27:59Z", "hours": 6.2281, "text": "006: the pool, the bound, and the storm that never got to happen Three jobs landed: a small worker pool with an atomic claim, retention finally observed deleting past its bound on a real run, and a decision about targets that never succeed. Still no second owned domain, so two scans running at once is pinned by a race test instead of watched live. The pool is three workers, one plain constant. The whole design is the claim: one SQL statement picks a queued row and flips it to running in the same breath, so two workers can never take the same row. A test runs two real processes over one database file with twelve queued rows, and together they claimed all twelve, no duplicates. A politeness rule rides on top: a queued scan waits while any scan of the same target, or any target at the same address, is running, so one host never gets swept by two workers at once. Watched it live: a burst of four scans on one host ran strictly one at a time, each starting within a millisecond of the previous finish. Boot recovery marked several stranded running rows failed at once, and a real kill mid-sweep recovered cleanly, the next queued scan picking up seconds later. Retention had never deleted anything, since the real bound is a hundred. Lowered it to five for a soak, then restored it. The prune deleted exactly the five oldest done rows in the same instant, findings and diffs went with them through the cascade, failed rows were untouched, and neither feed noticed. The never-succeeded decision: a target whose scans always fail used to be requeued every two seconds, forever, hammering a host that’s already failing. Now any finished scan resets the cadence, so a failing target is retried once per cadence like a healthy one. Cost, written down: a failed manual scan delays the next scheduled one. One tooling incident: leftover watchers went deaf partway through, and my cleanup matched its own command line and killed a mix of shells and watchers. Watchers get a pidfile now."}, {"post_id": 77487, "ts": "2026-10-07T06:06:47Z", "hours": 9.1194, "text": "005: the window armed, and the run that went dark Planned three things: catch the scheduler firing against a real clock, get a photo of a populated changes feed, and if there was room, add a retention limit to the scans table. The retention part landed clean. The clock-watching part did not, since the whole attempt crashed unexpectedly partway through and came back much later with only a partial trail left behind. Retention is simple and real: keep the last hundred completed scans per target, prune right after a scan finishes, never let a failed cleanup corrupt a scan that actually succeeded. Deleting an old scan correctly drags its stored history with it, since nothing on screen ever looks back further than the limit already allows anyway. The near miss is worth writing down. A log line looked exactly like proof the real scheduler behavior had finally been caught live. It was not, a different unrelated row fired for an unrelated reason, and it nearly got written up as the real finding before a second look caught it. Worse, the machine’s own clock had been wrong for the entire stretch, quietly off by a meaningful margin, so no timing claim from that window can be trusted. Every timing tool now stamps both the wall clock and a separate monotonic clock side by side, so drift shows up honestly instead of lying silently. Someone else picked up the real observation properly, on a trustworthy clock, the same day. One real bug got caught and fixed regardless: a visual check of the live pages turned up literal broken source text rendering in production on every page, leftover from unrelated commits, plus a stray constant pasted into the middle of an unrelated import. Both fixed and disclosed rather than skipped past. The actual lesson: the product held up fine through all of it. The environment around it, crashes, clock errors, lost caches, was what actually failed this time."}, {"post_id": 77153, "ts": "2026-10-05T20:04:08Z", "hours": 5.2897, "text": "004: the feed and the clock Two real jobs this time, since a monitor that rescans itself is useless if nobody can see what changed without opening every target by hand. Gave the changes feed a real home across all targets at once, and then verified the scheduler against an actual running clock instead of just faking the passage of time. The feed now lives on the dashboard as one shared section instead of being buried per target. The part that actually matters: both the per-target view and the new dashboard view call the exact same underlying function with the same inputs, so there’s no way for them to ever quietly disagree, a test pins that guarantee directly. Then watched the scheduler live instead of trusting it on paper. Queued three scans back to back and watched a live monitor poll the database every tenth of a second: each one started within a millisecond of the previous finishing, strictly one at a time, exactly as claimed. Let the scheduler run untouched for a few minutes after and it correctly saw nothing was due yet, zero extra scans fired. Then did a real crash test, killed the server mid-scan for real, and on restart the interrupted scan correctly recorded itself as failed with an honest reason and a real timestamp, while the next queued scan picked up normally right after. Nothing stalled, nothing doubled up. Also added a small “last changed” column to the main table, reading how long ago a target last actually recorded a real change, falling back to an honest dash instead of a false zero when there’s simply no history to look back through. Honest gaps left standing: the scheduler’s actual auto-triggered scan path still hasn’t fired against a real clock, since nothing happened to go stale during this run, and the fully populated version of the new feed has never actually been seen live, since the test target just didn’t flap this time."}, {"post_id": 75862, "ts": "2026-10-01T11:37:09Z", "hours": 5.3144, "text": "003: the monitor runs on its own Three things landed, and one caught a real bug in the tool itself. Targets now get rescanned automatically on a fixed cadence instead of only when someone manually triggers one, with guards so a slow scan never piles another behind it and a crash-interrupted scan gets marked failed on restart instead of stalling the cadence forever. The bug lived in that scheduler. A raw SQL fragment had a column reference that wasn’t properly scoped, so inside a nested subquery it silently matched against the wrong table entirely, meaning every tick thought every target was already stale and due again. The worker rescanned the test target seventeen times in about three minutes before anyone noticed. Killed it, fixed the query by hand, and pinned the actual generated SQL in a test so the same mistake fails loudly next time instead of quietly hammering a shared target. That accidental storm also proved the flap-detection design works for real: the scheduled runs watched the flaky test port close three times, catch it opening once with exactly the single expected unconfirmed alert, then stay quiet through seven more scans that all agreed. One honest announcement, then silence, no crying wolf. Extended certificate checking from just the main port to the mail ports too, and testing it against a real mail server caught another real bug, the handshake was sending the resolved IP address as the server name instead of the actual domain, so every check failed with a false hostname mismatch on a certificate that was actually fine. Fixed to match what a real browser does, and the same server that falsely failed a minute earlier came back clean. Also did another full visual pass and caught a few smaller things left over: red still marking a normal state, a decorative pulsing dot next to text that already said the same thing, inconsistent spacing across tables, and a rare timing mismatch between server-rendered and client-rendered relative timestamps."}, {"post_id": 75721, "ts": "2026-09-30T21:06:20Z", "hours": 4.35, "text": "002: the ui rework The scanner works and the loop is honest, but the frontend read like it came off an assembly line. Screenshotted every page with real data and judged each one as a skeptical stranger: does one person’s point of view show here, or does it pattern-match a template. Verdict: every shot patterned. Terminal-cosplay monospace headline, a numbered marketing-style “how it works” section, prose before any real output, tinted pill badges doing what a plain word could do, a green accent spent purely on decoration. That same review caught two real bugs, not the code review. Findings rendered worst-last instead of worst-first, so the most important result sat at the bottom. And a completely expected, normal state rendered in alarm red, exactly the thing that trains people to ignore red. Rebuilt around one stance: paper, not a dashboard. Off-white background, no rounded corners, no shadows, no gradients. Tables are the interface. Monospace only for actual data, ports, tokens, timestamps. Color appears exactly once, for severity, nothing else. The landing page now shows a real report pulled live from the database instead of marketing copy. Shipped port banner grabbing too, so an open port says what’s listening instead of a bare number. One real security call won along the way: a first draft quietly disabled certificate validation to read self-signed certs, and that got reverted, since a self-signed cert is exactly what a monitoring tool should flag, not quietly read through. Also added a real diff feed between scans. A flaky test target’s port flips open and closed between runs, so announcing every change instantly would be worthless noise. Settled on showing a change immediately but marked unconfirmed until two of the last three scans agree, resolving a one-scan flap back to its real state too. Still missing: scheduled rescans, so the feed only moves when someone manually triggers a scan, and mail TLS ports are identified but not checked for certificate expiry yet."}, {"post_id": 75473, "ts": "2026-09-30T05:53:13Z", "hours": 5.0386, "text": "001: the first loop works OpenPorts watches a domain from the outside and reports what it exposes: open ports, TLS certificates on their way out, mail records that let anyone spoof you, headers that give away the stack. The first full loop went end to end: add a domain, publish one TXT record to prove you own it, then the scanner runs. No record, no scan, one exception for the public test target Nmap itself runs for scanner builders. The scanner stays deliberately modest: one connect sweep over the hundred most likely ports, a TLS handshake to read the certificate, a few DNS lookups for spoofing protection, and three small HTTP checks. Nothing sends a payload, nothing probes services. A full scan takes under three seconds. Two real bugs worth writing down. First, the hand-assembled port list was just wrong, missing port 3389 entirely, so the single highest-severity finding in the whole catalog could never actually fire. A boring test that just checks a list of numbers felt like pure ceremony right up until it caught exactly that. Second, the test target’s port 80 turned out flaky in the worst way for a monitoring product: sometimes it answers fully, sometimes the connection opens but the request just hangs until timeout, and reported findings silently change between runs though nothing on the customer’s end did anything. Now recording exactly what the network said instead of pretending every check came back clean; confirming a change twice before reporting it is next. Architecture choices so far: a simple embedded database instead of a separate one to babysit, and one plain interval-based worker in the main process instead of real job infrastructure, the least moving parts that still survives a restart without double-scanning. What doesn’t work yet: no service identification on open ports, TLS only checked when the main web port answers, and only one scan at a time. Next: naming what’s running on each open port, scheduled rescans, and diffing between scans, since “this port showed up since yesterday” is the real product."}]...
|
Title: Openport by @xenoaitham | Stardance
Devlog Title: Openport by @xenoaitham | Stardance
Devlogs:
001: the first loop works OpenPorts watches a domain from the outside and reports what it exposes: open ports, TLS certificates on their way out, mail records that let anyone spoof you, headers that give away the stack. The first full loop went end to end: add a domain, publish one TXT record to prove you own it, then the scanner runs. No record, no scan, one exception for the public test target Nmap itself runs for scanner builders. The scanner stays deliberately modest: one connect sweep over the hundred most likely ports, a TLS handshake to read the certificate, a few DNS lookups for spoofing protection, and three small HTTP checks. Nothing sends a payload, nothing probes services. A full scan takes under three seconds. Two real bugs worth writing down. First, the hand-assembled port list was just wrong, missing port 3389 entirely, so the single highest-severity finding in the whole catalog could never actually fire. A boring test that just checks a list of numbers felt like pure ceremony right up until it caught exactly that. Second, the test target’s port 80 turned out flaky in the worst way for a monitoring product: sometimes it answers fully, sometimes the connection opens but the request just hangs until timeout, and reported findings silently change between runs though nothing on the customer’s end did anything. Now recording exactly what the network said instead of pretending every check came back clean; confirming a change twice before reporting it is next. Architecture choices so far: a simple embedded database instead of a separate one to babysit, and one plain interval-based worker in the main process instead of real job infrastructure, the least moving parts that still survives a restart without double-scanning. What doesn’t work yet: no service identification on open ports, TLS only checked when the main web port answers, and only one scan at a time. Next: naming what’s running on each open port, scheduled rescans, and diffing between scans, since “this port showed up since yesterday” is the real product.
002: the ui rework The scanner works and the loop is honest, but the frontend read like it came off an assembly line. Screenshotted every page with real data and judged each one as a skeptical stranger: does one person’s point of view show here, or does it pattern-match a template. Verdict: every shot patterned. Terminal-cosplay monospace headline, a numbered marketing-style “how it works” section, prose before any real output, tinted pill badges doing what a plain word could do, a green accent spent purely on decoration. That same review caught two real bugs, not the code review. Findings rendered worst-last instead of worst-first, so the most important result sat at the bottom. And a completely expected, normal state rendered in alarm red, exactly the thing that trains people to ignore red. Rebuilt around one stance: paper, not a dashboard. Off-white background, no rounded corners, no shadows, no gradients. Tables are the interface. Monospace only for actual data, ports, tokens, timestamps. Color appears exactly once, for severity, nothing else. The landing page now shows a real report pulled live from the database instead of marketing copy. Shipped port banner grabbing too, so an open port says what’s listening instead of a bare number. One real security call won along the way: a first draft quietly disabled certificate validation to read self-signed certs, and that got reverted, since a self-signed cert is exactly what a monitoring tool should flag, not quietly read through. Also added a real diff feed between scans. A flaky test target’s port flips open and closed between runs, so announcing every change instantly would be worthless noise. Settled on showing a change immediately but marked unconfirmed until two of the last three scans agree, resolving a one-scan flap back to its real state too. Still missing: scheduled rescans, so the feed only moves when someone manually triggers a scan, and mail TLS ports are identified but not checked for certificate expiry yet.
003: the monitor runs on its own Three things landed, and one caught a real bug in the tool itself. Targets now get rescanned automatically on a fixed cadence instead of only when someone manually triggers one, with guards so a slow scan never piles another behind it and a crash-interrupted scan gets marked failed on restart instead of stalling the cadence forever. The bug lived in that scheduler. A raw SQL fragment had a column reference that wasn’t properly scoped, so inside a nested subquery it silently matched against the wrong table entirely, meaning every tick thought every target was already stale and due again. The worker rescanned the test target seventeen times in about three minutes before anyone noticed. Killed it, fixed the query by hand, and pinned the actual generated SQL in a test so the same mistake fails loudly next time instead of quietly hammering a shared target. That accidental storm also proved the flap-detection design works for real: the scheduled runs watched the flaky test port close three times, catch it opening once with exactly the single expected unconfirmed alert, then stay quiet through seven more scans that all agreed. One honest announcement, then silence, no crying wolf. Extended certificate checking from just the main port to the mail ports too, and testing it against a real mail server caught another real bug, the handshake was sending the resolved IP address as the server name instead of the actual domain, so every check failed with a false hostname mismatch on a certificate that was actually fine. Fixed to match what a real browser does, and the same server that falsely failed a minute earlier came back clean. Also did another full visual pass and caught a few smaller things left over: red still marking a normal state, a decorative pulsing dot next to text that already said the same thing, inconsistent spacing across tables, and a rare timing mismatch between server-rendered and client-rendered relative timestamps.
004: the feed and the clock Two real jobs this time, since a monitor that rescans itself is useless if nobody can see what changed without opening every target by hand. Gave the changes feed a real home across all targets at once, and then verified the scheduler against an actual running clock instead of just faking the passage of time. The feed now lives on the dashboard as one shared section instead of being buried per target. The part that actually matters: both the per-target view and the new dashboard view call the exact same underlying function with the same inputs, so there’s no way for them to ever quietly disagree, a test pins that guarantee directly. Then watched the scheduler live instead of trusting it on paper. Queued three scans back to back and watched a live monitor poll the database every tenth of a second: each one started within a millisecond of the previous finishing, strictly one at a time, exactly as claimed. Let the scheduler run untouched for a few minutes after and it correctly saw nothing was due yet, zero extra scans fired. Then did a real crash test, killed the server mid-scan for real, and on restart the interrupted scan correctly recorded itself as failed with an honest reason and a real timestamp, while the next queued scan picked up normally right after. Nothing stalled, nothing doubled up. Also added a small “last changed” column to the main table, reading how long ago a target last actually recorded a real change, falling back to an honest dash instead of a false zero when there’s simply no history to look back through. Honest gaps left standing: the scheduler’s actual auto-triggered scan path still hasn’t fired against a real clock, since nothing happened to go stale during this run, and the fully populated version of the new feed has never actually been seen live, since the test target just didn’t flap this time.
005: the window armed, and the run that went dark Planned three things: catch the scheduler firing against a real clock, get a photo of a populated changes feed, and if there was room, add a retention limit to the scans table. The retention part landed clean. The clock-watching part did not, since the whole attempt crashed unexpectedly partway through and came back much later with only a partial trail left behind. Retention is simple and real: keep the last hundred completed scans per target, prune right after a scan finishes, never let a failed cleanup corrupt a scan that actually succeeded. Deleting an old scan correctly drags its stored history with it, since nothing on screen ever looks back further than the limit already allows anyway. The near miss is worth writing down. A log line looked exactly like proof the real scheduler behavior had finally been caught live. It was not, a different unrelated row fired for an unrelated reason, and it nearly got written up as the real finding before a second look caught it. Worse, the machine’s own clock had been wrong for the entire stretch, quietly off by a meaningful margin, so no timing claim from that window can be trusted. Every timing tool now stamps both the wall clock and a separate monotonic clock side by side, so drift shows up honestly instead of lying silently. Someone else picked up the real observation properly, on a trustworthy clock, the same day. One real bug got caught and fixed regardless: a visual check of the live pages turned up literal broken source text rendering in production on every page, leftover from unrelated commits, plus a stray constant pasted into the middle of an unrelated import. Both fixed and disclosed rather than skipped past. The actual lesson: the product held up fine through all of it. The environment around it, crashes, clock errors, lost caches, was what actually failed this time.
006: the pool, the bound, and the storm that never got to happen Three jobs landed: a small worker pool with an atomic claim, retention finally observed deleting past its bound on a real run, and a decision about targets that never succeed. Still no second owned domain, so two scans running at once is pinned by a race test instead of watched live. The pool is three workers, one plain constant. The whole design is the claim: one SQL statement picks a queued row and flips it to running in the same breath, so two workers can never take the same row. A test runs two real processes over one database file with twelve queued rows, and together they claimed all twelve, no duplicates. A politeness rule rides on top: a queued scan waits while any scan of the same target, or any target at the same address, is running, so one host never gets swept by two workers at once. Watched it live: a burst of four scans on one host ran strictly one at a time, each starting within a millisecond of the previous finish. Boot recovery marked several stranded running rows failed at once, and a real kill mid-sweep recovered cleanly, the next queued scan picking up seconds later. Retention had never deleted anything, since the real bound is a hundred. Lowered it to five for a soak, then restored it. The prune deleted exactly the five oldest done rows in the same instant, findings and diffs went with them through the cascade, failed rows were untouched, and neither feed noticed. The never-succeeded decision: a target whose scans always fail used to be requeued every two seconds, forever, hammering a host that’s already failing. Now any finished scan resets the cadence, so a failing target is retried once per cadence like a healthy one. Cost, written down: a failed manual scan delays the next scheduled one. One tooling incident: leftover watchers went deaf partway through, and my cleanup matched its own command line and killed a mix of shells and watchers. Watchers get a pidfile now.
007: the cadence on the real clock, and the gap that stands The oldest open question in the project closed: the six hour cadence fired on the real clock, no rewind, nothing inserted by hand. The scheduled scan appeared about a second after the mark, got claimed seven milliseconds later, finished in under four seconds, and stored the same empty diff as the one before it. Both feeds stayed honestly quiet. Every process watching it had died and the machine had been rebuilt around them, which didn’t matter, since the clock reads the database, not any process. One small decision along the way: the politeness check stays on one stored address per target. Matching every address would need an address history table inside the claim, real machinery for round-robin hosts a small company rarely has, and politeness is a courtesy, not a correctness property. Two lessons for the watching kit. Wiping the database with rm deafens any watcher, since it keeps polling the deleted file and the log just stops with no error, so restart it after every wipe, and after the migrate. And the production server doesn’t migrate, only dev does. The gap that stands: two owned targets sharing the cadence, and two scans running at once, still pinned by a race test instead of watched live. Two more runs checked, and the second went deeper. No DNS credentials anywhere, then a cloud CLI turned up with two accounts, one with a dead token and one that sees ten projects with the DNS service disabled on every one. There’s a difference between no panel and a panel one billable step away, and enabling it is a purchase on someone’s account, not something to do unprompted. Meanwhile the loop held every time: add the public test target, scan it, same four findings, port 80 splitting its personality between a 200 on the banner grab and a refused connection on the redirect check. It never flapped, so the populated changes feed has still never been seen on live data, and nothing was staged to force it.
022: v1.0 stamped, the gap priced a fourteenth time One headline: stamp v1.0. Not new scope, just a clean stamp on what already works, so a stranger can clone, install, run, add a domain, publish one TXT record, and get real reports every six hours. The owner added one rule above everything else: commit nothing and push nothing until they say the word, so every git step is prepared and held. The box rebooted again, the fifth pickup like it, and both handoff processes died with it. Restoring them took one command each. The database wasn’t empty this time, since the owner had seeded two scans, and that led to the best surprise: the seed had made the target six hours stale, so on boot the scheduler enqueued a scan by itself. First scheduled rescan on the real clock since the cadence was proven, no rewind, no hand-inserted row, no request in the log before it. Four independent sightings of the due branch now. The scratch got cleared: four places, thirteen lines, all dead comments, a duplicate export and an unused constant, with the test count at 56 before and after. The README got read as a stranger would read it, every claim checked against the code, and none lied. One omission fixed: a single line naming the Node version. The domain question got priced again, and the baseline held on every corner. The cloud CLI lists thirteen projects, and every one answered that the DNS API is disabled. Enabling it and creating a zone is a billable action nobody takes on their own behalf, so two targets on one cadence and two scans at once stay pinned by a race test instead of watched live. A fresh set of twelve screenshots came out clean, though the browser cache was gone again and had to be refetched. The changes feed still has never shown a populated state on live data: seven done scans, every diff empty, nothing staged to force one. The release steps are queued in order, waiting for the word: scratch commit, README commit, version stamp, tag, push, release.
Ships:
I made OpenPorts, an attack surface monitor for small companies: you add a domain, prove you own it by publishing one TXT record at _openports.<yourdomain> , and a scanner that lives inside the web app itself sweeps the 100 most common TCP ports, has one short conversation with every open port, reads the TLS certificate on 443 and the mail ports, and checks SPF, DMARC, MX, HSTS, the http to https redirect and the server header. Every scan is diffed against the previous one, changes are held unconfirmed until a second scan agrees, and verified targets are rescanned every six hours without anyone pressing anything. The whole product is one process and one SQLite file: no redis, no docker, no queue service, two commands to run. The hardest bug was one I inflicted on myself. The scheduler’s due query used ORM column objects inside a raw SQL fragment, the ORM rendered them unqualified, and inside a correlated subquery a bare id resolved to the wrong table, so the query compared every scan against itself and concluded the target was due on every two second tick. The worker scanned the demo host seventeen times in three minutes before I noticed. The fix was hand qualifying the table names and pinning the generated SQL in tests, so the next person who makes that mistake fails a test instead of discovering it from a host’s point of view. The second hard part was honesty under a flapping network: the demo host’s port 80 gives different answers to different conversations seconds apart, so a naive monitor would cry wolf on every run. Changes now announce immediately, tagged unconfirmed, and only confirm when two of the last three scans agree. I am proud that nothing on screen is faked. Findings are never staged; every number in the report came off the wire, including the disagreements, which the report prints instead of hiding. And I am proud of the gate: nothing is ever scanned until ownership is proven, the worker rechecks verification before touching the network, and the single exception is scanme.nmap.org, which the Nmap project runs for exactly this purpose. To test: open https://emotions-finger-earthquake-hints.trycloudflare.com in a browser, nothing to install. Click run scan again on the target and watch a real scan finish in about four seconds, then expand raw scan output to see what actually came off the wire. Or run it locally: npm install, npm run dev, then open http://localhost:4310....
|
1793008387.6056929
|
1793872387.6056929
|
|
67686
|
riggermortis by @xenoaitham | Stardance
|
xenoaitham
|
0
|
18.81
|
0
|
[]
|
[{"post_id": 76925, "ts": "202 [{"post_id": 76925, "ts": "2026-10-05T03:12:20Z", "hours": 10.9147, "text": "the sculpt wires into the product flow The proportion and volume sculpting work was measured and gated, but had no real user-facing path yet. That debt got paid: a new command line tool measures a reference image’s proportions and volume ratios into one deterministic file, and both the manual tool and the interactive in-app action now call the same shared function underneath, so they can’t quietly drift apart. The real proof was ordering: sculpt once at rest pose, then animate, and the sculpt has to survive byte-identically. It does, frame-one drift came out effectively zero across seventy checks. Three real bugs earned their keep. First, two test rigs sharing one scene made solved values look wrong, the real cause was one fixture already carrying an earlier sculpt while the other’s baseline measurement accidentally captured the overlapping shape of both figures at once. Took a full debugging ladder to isolate, fixed with a clean scene per case, a lesson the project had already learned once before, now learned twice. Second, baking an animation shifts frame numbers by one internally, so comparing a frame against its own neighbor instead of itself made results look dramatically worse than they actually were. A one-line offset fix, with the reasoning written directly into the check itself this time so it can’t get silently lost again. Third, comparing raw bone positions across an animated sequence turned out to be the wrong check entirely, since a position-based re-solve is supposed to compensate for the current pose’s rotation by design, not match it exactly. Redefined what the check actually verifies, and caught a related bug along the way: an assigned animation silently overrides a rest-pose snapshot unless that animation gets explicitly muted first. Landed with fifteen new tests, the full suite green, and every number comfortably inside its bar except one, a single rig type’s re-sculpt accuracy sits just barely over target, left as the next rough edge."}, {"post_id": 76391, "ts": "2026-10-03T11:46:33Z", "hours": 7.8906, "text": "volume from silhouette The third model decision is made and the volume feature is real. The engine now carries a third pinned model, a segmentation pass, plus a working body sculpt: feed it a reference shape and the character’s hip, waist, chest, and thigh widths move to match it, skeleton provably untouched. Getting there meant benchmarking five real candidate models on real hardware, checksums, speed, and accuracy each, rejecting six other families with the evidence written down. Funniest catch: the model built specifically for segmenting people was completely blind to the test case, zero accuracy, while the general-purpose model saw it fine and ran cheaper too. The mechanism authors real shape keys per body region, so the adjustable sliders are the solved math directly, and every pose/animation path downstream sees a completely unchanged skeleton. The real fight was realizing the first passing test was a lie. A whole-frame comparison technically passed on a completely unsculpted body, since the measurement was too insensitive to tell a correctly sculpted shape from an untouched one. Fixed by scoping comparisons to the actual body regions with no model in the loop, publishing a baseline next to every result so a cheating pass can’t hide again. Smaller lessons banked too: a slider silently defaulting to zero killed half its usable range, one rig type needed its math in a different coordinate space entirely or it silently did nothing, leftover scene state poisoned later measurements, and naive bone-weight assignment broke the hip region specifically. Numbers came out solid: worst-case regional accuracy clears the bar across every test case, width delivery lands exact to four decimal places, solved values track intended targets within about 3% through the real model, and resetting a sculpt restores the original mesh almost exactly. Next: wire both sculpts into the real user-facing flow, and prove the sculpt survives animation, set once, then animate, and the widths hold."}]...
|
Title: riggermortis by @xenoaitham | Stardance
De Title: riggermortis by @xenoaitham | Stardance
Devlogs:
volume from silhouette The third model decision is made and the volume feature is real. The engine now carries a third pinned model, a segmentation pass, plus a working body sculpt: feed it a reference shape and the character’s hip, waist, chest, and thigh widths move to match it, skeleton provably untouched. Getting there meant benchmarking five real candidate models on real hardware, checksums, speed, and accuracy each, rejecting six other families with the evidence written down. Funniest catch: the model built specifically for segmenting people was completely blind to the test case, zero accuracy, while the general-purpose model saw it fine and ran cheaper too. The mechanism authors real shape keys per body region, so the adjustable sliders are the solved math directly, and every pose/animation path downstream sees a completely unchanged skeleton. The real fight was realizing the first passing test was a lie. A whole-frame comparison technically passed on a completely unsculpted body, since the measurement was too insensitive to tell a correctly sculpted shape from an untouched one. Fixed by scoping comparisons to the actual body regions with no model in the loop, publishing a baseline next to every result so a cheating pass can’t hide again. Smaller lessons banked too: a slider silently defaulting to zero killed half its usable range, one rig type needed its math in a different coordinate space entirely or it silently did nothing, leftover scene state poisoned later measurements, and naive bone-weight assignment broke the hip region specifically. Numbers came out solid: worst-case regional accuracy clears the bar across every test case, width delivery lands exact to four decimal places, solved values track intended targets within about 3% through the real model, and resetting a sculpt restores the original mesh almost exactly. Next: wire both sculpts into the real user-facing flow, and prove the sculpt survives animation, set once, then animate, and the widths hold.
the sculpt wires into the product flow The proportion and volume sculpting work was measured and gated, but had no real user-facing path yet. That debt got paid: a new command line tool measures a reference image’s proportions and volume ratios into one deterministic file, and both the manual tool and the interactive in-app action now call the same shared function underneath, so they can’t quietly drift apart. The real proof was ordering: sculpt once at rest pose, then animate, and the sculpt has to survive byte-identically. It does, frame-one drift came out effectively zero across seventy checks. Three real bugs earned their keep. First, two test rigs sharing one scene made solved values look wrong, the real cause was one fixture already carrying an earlier sculpt while the other’s baseline measurement accidentally captured the overlapping shape of both figures at once. Took a full debugging ladder to isolate, fixed with a clean scene per case, a lesson the project had already learned once before, now learned twice. Second, baking an animation shifts frame numbers by one internally, so comparing a frame against its own neighbor instead of itself made results look dramatically worse than they actually were. A one-line offset fix, with the reasoning written directly into the check itself this time so it can’t get silently lost again. Third, comparing raw bone positions across an animated sequence turned out to be the wrong check entirely, since a position-based re-solve is supposed to compensate for the current pose’s rotation by design, not match it exactly. Redefined what the check actually verifies, and caught a related bug along the way: an assigned animation silently overrides a rest-pose snapshot unless that animation gets explicitly muted first. Landed with fifteen new tests, the full suite green, and every number comfortably inside its bar except one, a single rig type’s re-sculpt accuracy sits just barely over target, left as the next rough edge....
|
1792468202.9250567
|
1793332202.9250567
|
|
69520
|
UNDERCROFT by @xenoaitham | Stardance
|
xenoaitham
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: UNDERCROFT by @xenoaitham | Stardance
|
1792857077.0273328
|
1793721077.0273328
|
|
16920
|
My awesome macropad! by @xeno3ra | Stardance
|
xeno3ra
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xeno3ra | Stardanc Title: My awesome macropad! by @xeno3ra | Stardance...
|
1792666218.0765321
|
1793271018.0765321
|
|
17045
|
Zenith by @xeno3ra | Stardance
|
xeno3ra
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Zenith by @xeno3ra | Stardance
|
1793210070.759751
|
1793814870.759751
|
|
22838
|
XenoDeal by @xeno3ra | Stardance
|
xeno3ra
|
0
|
11.12
|
0
|
[]
|
[{"post_id": 14861, "ts": "202 [{"post_id": 14861, "ts": "2026-06-24T04:01:13Z", "hours": 3.6653, "text": "Devlog #3 Today, I have finished Phase 2; and everything is working! On top of finishing Phase 2, I have started the multi-user support which I have decided to add. The Ship Tabacle Before starting work on Phase 3, I ended up finding out from shipping guidelines that the project, quote “Bots (Discord, Slack, etc…): It has to be hosted! … You can’t leave your bot unhosted with only source code.” Also implying that it has to be… “Multi-User” As a result of this, I have decided to add multi-user support, by giving one wwebjs Client to each user, managed by the new client manager: clientPool.js that allow’s everyone to have their own “instance,” group selection, and notifications. The upside to this way of solving the problem is that most of the components, for example: Classifier, Alerts System, DB Schema, all of that can stay the same, only requiring a few changes to make it compatible for the new Multi User System. With all of these changes; the new system to register and use the bot is this: User DMs the bot /start Bot asks for their WhatsApp number They reply with it spawnClient(chatId, phone) is called wwebjs emits qr , we call requestPairingCode(phone) instead of sending a QR image The user receives a code like ABCD-1234 , enters it in WhatsApp → Linked Devices, anddd… Connected ✅ This simlifies the bot to be User Friendly, to host, and use + allows me to still be able to ship Problems Encountered 1. “Houston! We have an IPv6 Problem…” Problem: bot.launch() was timing out during the getMe handshake with Telegram at random. Worked sometimes, failed other times. **Fix:**Added require('dns').setDefaultResultOrder('ipv4first') on index.js , plus a keepAlive HTTPS agent on the Telegraf instance. 2. “Silent Treatment” Problem: Bot received /start , asked for phone number, user replied… and you get ghosted. Fix: One missing String() cast in /start . Took way too long to find. 3. “The Ghost of Chromium Past” Problem: Previous test run left a Chromium process hanging. Next launch: “The browser is already running for auth_data/session-7145622406.” Fix: pkill -f chromium + delete the session folder. 4. “t” Problem: requestPairingCode threw a single-letter minified error: t . No stack trace, no message. Just… t . Fix: Drop the alpha version, and pin the stable 2.3000.1017054665 instead. 5. “The Error in the Error Handler’s House” Problem: After bug 4 threw, the catch block tried to DM the user an error message. That also timed out, with the SAME cold IPv6 issue, firing during Chromium’s initial page load which was already hammering the event loop. Fix: Wrapped the notification send in its own try/catch . A failed notification shouldn’t throw an unhandled rejection on top of the original error. What’s Next Finish commands: /addgroup , /threshold , /categories , /status , /deals restoreAllSessions() : reconnect everyone on process restart messageHandler.js : wire live capture per subscriber sendDealAlert() : fan-out to all matching subscribers Sold detection Dashboard post-ship First public ship"}, {"post_id": 13846, "ts": "2026-06-22T18:04:33Z", "hours": 4.9544, "text": "Devlog 2: XenoDeal | The AI Turns On (And Starts Eating Tokens) June 22 Since the previous devlog (sorry for missing yesterday), I have gotten the AI System Implemented, and Filtering in order. WhatsApp has caused MORE problems, and luckily I fixed them. (But not the Logout Crash) Besides that, the day (and a half) were easy. Classifier And Telegram The Main, MAJOR piece of this devlog and the changes I’ve made since devlog one is src/cron/classifier.js . It’s a background process that does four main things: Grabs Unprocessed Messages from the DB in Batches Runs a separate pre-filter file, that removes Obvious Noise and Junk from the Batch Sends Candidates to AI Provider for full classification Writes the result to the new deals table and marks the message as processed Roughly ~150 Messages are still not processed, from my testing batch, gathered from Phase 1, and it is still expanding. This is not just the most important part of the project, it’s the… orchestrator if you will. The batch size is dynamic, and scales every tick based on backlog and load. This is mainly important during boot after downtime as WWJS just replays missed messages as Live Events, causing a MENTAL wave of messages, and this allows the backlog to finish faster. async function getBatchSize () { const r = await pool . query ( ' SELECT COUNT(*) FROM messages WHERE processed = false ' ); const pending = parseInt ( r . rows [ 0 ]. count ); if ( pending > 100 ) return MAX_BATCH ; // 100 if ( pending > 20 ) return 50 ; return MIN_BATCH ; // 20 } The one architectural decision I have made is to DECOUPLE the poller and message create handlers. They can run without the other, and they work at their own pace, so live messages don’t get blocked from inserting, thus less profit. For Telegram, I just added a threshold for me to get notified about a listing. If it’s score is above 65, it will send me all the details of the listing, the group name, and the original message. An example is attached as an image. Bugs 1.) “Temperature Card” Problem: Same listing was scoring differently Fix: Set Temperature to 0.2 2.) “Sorry, I didn’t understand, please try rephrasing that” Problem: The AI System thought that it was looking for deals for the End Buyer + Hallucinating Good Condition without Evidence Fix: Rewrite Prompt to be more detailed 3.) “Lid, a Big Lid with no Phone # in it” Problem: Whatsapp returns a lid ID instead of a number Fix: Used an approach using client.pupPage and window.require 4.) “Have you seen Chromium anywhere?” Problem: WhatsApp updated and the injection of WWJS made Chromium “Context Crash” Fix: Pin a specific version of WhatsApp What’s Next The Dashboard has been pushed back until after the first ship, and as phase 2 has been complete, now phase three is the following: Train and Implement ML for filtering and deals Add Multi-User Support Add Setup Flow to Telegram Add /cmds to Telegram Polish for First Ship"}, {"post_id": 12896, "ts": "2026-06-21T03:47:39Z", "hours": 2.5011, "text": "Devlog: XenoDeal | The Listener Wakes Up June 20 Today was a bit hard (it’s the first day on this project, and I’m catching strays breh). I started with: Planning out the infra Making the project base The stack for this one is: PostgreSQL, Node.js, Telegraf, and wwebjs. I ended up building out the basis for the Telegram, PostgreSQL, and WhatsApp wrappers. Telegram and Postgres were easy, being a few lines each, for now. WhatsApp, being the main part of the app, wanted to give me problems. Four total. Issue 1: Puppeteer ghosting me. Setting up the project, making sure init and env loading worked across all files, Node kept complaining about “Puppeteer Missing.” I’d just installed it, so I assumed it was fine. Turns out pnpm takes security seriously and silently blocks Puppeteer’s install script by default. To make it worse, I fat-fingered Enter instead of Space on the approve-builds screen, so even the prompt to fix it slipped past me. Couldn’t figure out how to re-trigger the script, so I just pointed it at my system Chromium instead: const client = new Client ({ puppeteer : { executablePath : ' /usr/bin/chromium ' , headless : true , args : [ ' --no-sandbox ' , ' --disable-setuid-sandbox ' ] }, authStrategy : new LocalAuth ({ dataPath : ' auth_data ' }) }); Issue 2: The Logout Crash. I wanted to check that client.on('disconnected') actually fires correctly, so I tested it the easy way: logged out the linked WhatsApp session from my phone. Instead of a clean disconnect, client.on('ready') fired three times , then it crashed: Failed to add page binding with name onQRChangedEvent: window['onQRChangedEvent'] already exists! Best guess: wwebjs trying to inject its page bindings into a page that already had them. Possibly a [email protected] version mismatch against what [email protected] actually expects internally, but I’m not fully sure that’s the real cause yet. Problem for another day. Issue 3: The Silent Hang. Whilst testing the LocalAuth implementation, I Ctrl+C’d the process without realizing Chromium leaves behind a SingletonLock file. Next launch just hung indefinitely; no warning, no error, nothing. Found that out the hard way. I ended up clearing the stale lock and added this so it can’t happen again: process . on ( ' SIGINT ' , async () => { await client . destroy (); process . exit ( 0 ); }); tl;dr: It lets Chromium clean up after itself on every manual stop, instead of leaving a corpse behind for next time. Issue 4: the Date/Time Problem. Setting up message logging, I converted msg.timestamp (Unix seconds) to milliseconds for Postgres with msg.timestamp * 1000 . It wasn’t enough. Every insert failed with: date/time field value out of range: \"1782000093000\" Turns out pg doesn’t know what to do with a raw JS number where it expects a date, and just stringifies it and Postgres rejects the result outright. Had to wrap it in an actual Date object: new Date ( msg . timestamp * 1000 ) (Need to double check: I remember it still not behaving right away even after this fix, possibly just the client needing a moment to fully reconnect after restart rather than the date fix itself being incomplete. Worth confirming next time it comes up.) What’s Next So… reads design docs , according to this, I’ll be establishing Core Intelligence next. Second most exciting part of the whole build. Covers: Claude integration (analyze each listing, provide a ranking) Sold tracking The dashboard (PS: It did end up working)"}]...
|
Title: XenoDeal by @xeno3ra | Stardance
Devlogs:
Title: XenoDeal by @xeno3ra | Stardance
Devlogs:
Devlog: XenoDeal | The Listener Wakes Up June 20 Today was a bit hard (it’s the first day on this project, and I’m catching strays breh). I started with: Planning out the infra Making the project base The stack for this one is: PostgreSQL, Node.js, Telegraf, and wwebjs. I ended up building out the basis for the Telegram, PostgreSQL, and WhatsApp wrappers. Telegram and Postgres were easy, being a few lines each, for now. WhatsApp, being the main part of the app, wanted to give me problems. Four total. Issue 1: Puppeteer ghosting me. Setting up the project, making sure init and env loading worked across all files, Node kept complaining about “Puppeteer Missing.” I’d just installed it, so I assumed it was fine. Turns out pnpm takes security seriously and silently blocks Puppeteer’s install script by default. To make it worse, I fat-fingered Enter instead of Space on the approve-builds screen, so even the prompt to fix it slipped past me. Couldn’t figure out how to re-trigger the script, so I just pointed it at my system Chromium instead: const client = new Client ({ puppeteer : { executablePath : ' /usr/bin/chromium ' , headless : true , args : [ ' --no-sandbox ' , ' --disable-setuid-sandbox ' ] }, authStrategy : new LocalAuth ({ dataPath : ' auth_data ' }) }); Issue 2: The Logout Crash. I wanted to check that client.on('disconnected') actually fires correctly, so I tested it the easy way: logged out the linked WhatsApp session from my phone. Instead of a clean disconnect, client.on('ready') fired three times , then it crashed: Failed to add page binding with name onQRChangedEvent: window['onQRChangedEvent'] already exists! Best guess: wwebjs trying to inject its page bindings into a page that already had them. Possibly a [email protected] version mismatch against what [email protected] actually expects internally, but I’m not fully sure that’s the real cause yet. Problem for another day. Issue 3: The Silent Hang. Whilst testing the LocalAuth implementation, I Ctrl+C’d the process without realizing Chromium leaves behind a SingletonLock file. Next launch just hung indefinitely; no warning, no error, nothing. Found that out the hard way. I ended up clearing the stale lock and added this so it can’t happen again: process . on ( ' SIGINT ' , async () => { await client . destroy (); process . exit ( 0 ); }); tl;dr: It lets Chromium clean up after itself on every manual stop, instead of leaving a corpse behind for next time. Issue 4: the Date/Time Problem. Setting up message logging, I converted msg.timestamp (Unix seconds) to milliseconds for Postgres with msg.timestamp * 1000 . It wasn’t enough. Every insert failed with: date/time field value out of range: "1782000093000" Turns out pg doesn’t know what to do with a raw JS number where it expects a date, and just stringifies it and Postgres rejects the result outright. Had to wrap it in an actual Date object: new Date ( msg . timestamp * 1000 ) (Need to double check: I remember it still not behaving right away even after this fix, possibly just the client needing a moment to fully reconnect after restart rather than the date fix itself being incomplete. Worth confirming next time it comes up.) What’s Next So… reads design docs , according to this, I’ll be establishing Core Intelligence next. Second most exciting part of the whole build. Covers: Claude integration (analyze each listing, provide a ranking) Sold tracking The dashboard (PS: It did end up working)
Devlog 2: XenoDeal | The AI Turns On (And Starts Eating Tokens) June 22 Since the previous devlog (sorry for missing yesterday), I have gotten the AI System Implemented, and Filtering in order. WhatsApp has caused MORE problems, and luckily I fixed them. (But not the Logout Crash) Besides that, the day (and a half) were easy. Classifier And Telegram The Main, MAJOR piece of this devlog and the changes I’ve made since devlog one is src/cron/classifier.js . It’s a background process that does four main things: Grabs Unprocessed Messages from the DB in Batches Runs a separate pre-filter file, that removes Obvious Noise and Junk from the Batch Sends Candidates to AI Provider for full classification Writes the result to the new deals table and marks the message as processed Roughly ~150 Messages are still not processed, from my testing batch, gathered from Phase 1, and it is still expanding. This is not just the most important part of the project, it’s the… orchestrator if you will. The batch size is dynamic, and scales every tick based on backlog and load. This is mainly important during boot after downtime as WWJS just replays missed messages as Live Events, causing a MENTAL wave of messages, and this allows the backlog to finish faster. async function getBatchSize () { const r = await pool . query ( ' SELECT COUNT(*) FROM messages WHERE processed = false ' ); const pending = parseInt ( r . rows [ 0 ]. count ); if ( pending > 100 ) return MAX_BATCH ; // 100 if ( pending > 20 ) return 50 ; return MIN_BATCH ; // 20 } The one architectural decision I have made is to DECOUPLE the poller and message create handlers. They can run without the other, and they work at their own pace, so live messages don’t get blocked from inserting, thus less profit. For Telegram, I just added a threshold for me to get notified about a listing. If it’s score is above 65, it will send me all the details of the listing, the group name, and the original message. An example is attached as an image. Bugs 1.) “Temperature Card” Problem: Same listing was scoring differently Fix: Set Temperature to 0.2 2.) “Sorry, I didn’t understand, please try rephrasing that” Problem: The AI System thought that it was looking for deals for the End Buyer + Hallucinating Good Condition without Evidence Fix: Rewrite Prompt to be more detailed 3.) “Lid, a Big Lid with no Phone # in it” Problem: Whatsapp returns a lid ID instead of a number Fix: Used an approach using client.pupPage and window.require 4.) “Have you seen Chromium anywhere?” Problem: WhatsApp updated and the injection of WWJS made Chromium “Context Crash” Fix: Pin a specific version of WhatsApp What’s Next The Dashboard has been pushed back until after the first ship, and as phase 2 has been complete, now phase three is the following: Train and Implement ML for filtering and deals Add Multi-User Support Add Setup Flow to Telegram Add /cmds to Telegram Polish for First Ship
Devlog #3 Today, I have finished Phase 2; and everything is working! On top of finishing Phase 2, I have started the multi-user support which I have decided to add. The Ship Tabacle Before starting work on Phase 3, I ended up finding out from shipping guidelines that the project, quote “Bots (Discord, Slack, etc…): It has to be hosted! … You can’t leave your bot unhosted with only source code.” Also implying that it has to be… “Multi-User” As a result of this, I have decided to add multi-user support, by giving one wwebjs Client to each user, managed by the new client manager: clientPool.js that allow’s everyone to have their own “instance,” group selection, and notifications. The upside to this way of solving the problem is that most of the components, for example: Classifier, Alerts System, DB Schema, all of that can stay the same, only requiring a few changes to make it compatible for the new Multi User System. With all of these changes; the new system to register and use the bot is this: User DMs the bot /start Bot asks for their WhatsApp number They reply with it spawnClient(chatId, phone) is called wwebjs emits qr , we call requestPairingCode(phone) instead of sending a QR image The user receives a code like ABCD-1234 , enters it in WhatsApp → Linked Devices, anddd… Connected ✅ This simlifies the bot to be User Friendly, to host, and use + allows me to still be able to ship Problems Encountered 1. “Houston! We have an IPv6 Problem…” Problem: bot.launch() was timing out during the getMe handshake with Telegram at random. Worked sometimes, failed other times. **Fix:**Added require('dns').setDefaultResultOrder('ipv4first') on index.js , plus a keepAlive HTTPS agent on the Telegraf instance. 2. “Silent Treatment” Problem: Bot received /start , asked for phone number, user replied… and you get ghosted. Fix: One missing String() cast in /start . Took way too long to find. 3. “The Ghost of Chromium Past” Problem: Previous test run left a Chromium process hanging. Next launch: “The browser is already running for auth_data/session-7145622406.” Fix: pkill -f chromium + delete the session folder. 4. “t” Problem: requestPairingCode threw a single-letter minified error: t . No stack trace, no message. Just… t . Fix: Drop the alpha version, and pin the stable 2.3000.1017054665 instead. 5. “The Error in the Error Handler’s House” Problem: After bug 4 threw, the catch block tried to DM the user an error message. That also timed out, with the SAME cold IPv6 issue, firing during Chromium’s initial page load which was already hammering the event loop. Fix: Wrapped the notification send in its own try/catch . A failed notification shouldn’t throw an unhandled rejection on top of the original error. What’s Next Finish commands: /addgroup , /threshold , /categories , /status , /deals restoreAllSessions() : reconnect everyone on process restart messageHandler.js : wire live capture per subscriber sendDealAlert() : fan-out to all matching subscribers Sold detection Dashboard post-ship First public ship...
|
1792774465.7857127
|
1793379265.7857127
|
|
12893
|
Untitled project by @xenapa8745 | Stardance
|
xenapa8745
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled project by @xenapa8745 | Stardance
|
1792633923.9494107
|
1793238723.9494107
|
|
26860
|
My awesome macropad! by @xemerius | Stardance
|
xemerius
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xemerius | Stardan Title: My awesome macropad! by @xemerius | Stardance...
|
1793156154.059514
|
1793760954.059514
|
|
27009
|
My first slack bot! by @xemerius | Stardance
|
xemerius
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @xemerius | Stardanc Title: My first slack bot! by @xemerius | Stardance...
|
1792633817.5672915
|
1793238617.5672915
|
|
8377
|
Nautica API by @xellu | Stardance
|
xellu
|
1
|
26.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-15T18:37:11Z", "hours": 26.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I’ve updated the Service Manager, including the dependency resolver. These changes include: New lifecycle hook “onSetup”, intended for setting up databases, etc. I’ve mostly added this to split “start servers” and “setup things” all being in onStart. This way the separation between those 2 tasks is clear and helps to eliminate certain race conditions. Toggle switches are now generated automatically Before you had to manually declare a key in a config in onInstall, and then read it in isEnabled, which was just extra boilerplate. So I automated the process in the Service class. “?”, “:after” and “:after?” parameters for dependencies Before this, the boot order was still fragile even with dependencies defined, because the ability to define a dependency, and make it start only AFTER your dependency is initialized wasn’t a thing. Now you can do this by simply appending “:after” to the dependency name. “?” at the end also makes the dependency optional. Few fixes relating to dependency resolution and boot orders HTTP API Got a decently big update as well.. The performance is now up ~70% from previous versions, finally surpassing FastAPI, I’ve achieved this adding an option to disable unnecessary messages from being logged. Which only goes to show how heavy the logging manager I use is, but I doubt I’ll be rewriting it, since the way it is now helps with DX. Response validation using “@HTTP.Responses(…)” and ReplyModels: Before you were able to only validate what’s coming in, but not what’s going out. The validator has a strict mode, which when enabled adds an extra layer of “security”. If strict mode is disabled, the responses are only used for OpenAPI docs generation. Tho the framework may still complain if you’re sending invalid responses. Nested object validation and Require.ListOf Static methods in Reply Since the framework is built on Starlette, you may need to use Starlette’s responses in some cases. OpenAPI Docs generation This was kinda a big thing on my list ever since I realized that I can automatically generate SDKs instead of having to write request calls manually. I also wanted to add a way to expose the docs with an endpoint, but I’m holding off on that. The Package registry & manager were introduced as well. The package registry it itself built on Nautica, and works with the package manager integrated into the Nautica’s CLI. Likewise I’ve started work on the Landing page & docs website for the framework, but I’m putting it off for a bit, because of finals. I’ve also fixed countless bugs, refactored things, and over all made many QoL changes, which helped to make the framework feel more polished. This might be a strange project, since I’m somewhat “reinventing the wheel”, but I really didn’t like the way FastAPI, Flask and other Python HTTP frameworks work. It basically handles ONLY the http part, which is fine, but in bigger projects YOU have to manage everything else around it. When I was building small apps it wasn’t that big of an issue, but it became pretty apparent in bigger projects. The complexity and boilerplate that comes with large projects isn’t something I can handle well, while also having to enforce my own conventions. I made Nautica to fix these issues, and I’d say I succeeded. The boilerplate that’s needed per route is minimal, compared to other frameworks; The package manager adds an intuitive way to add plugins (services, packages), and the service system itself does a lot of the heavy lifting for you, by automatically deciding on the boot order instead of you having to write do it explicitly using imports, etc. In conclusion, Nautica takes away some freedom and in exchange gives you structure, less boilerplate and tools to debug your code, which makes shipping apps easier and faster.", "repo": "https://github.com/xellu/nautica-api", "demo": "https://napm.xellu.xyz/"}]...
|
[{"post_id": 9382, "ts": "2026 [{"post_id": 9382, "ts": "2026-06-15T18:35:53Z", "hours": 0.2822, "text": "A showcase of what Nautica can actually do ~20% faster than FastAPI ( https://github.com/xellu/nautica-api/wiki/Performance-Benchmark ) See Nautica in action: https://napm.xellu.xyz/ ( https://github.com/xellu/nautica-package-manager ) A video demonstration:"}, {"post_id": 9251, "ts": "2026-06-15T15:12:52Z", "hours": 3.4914, "text": "I’ve released v3.2.2, the new things there include: OpenAPI Docs generator Changed expression for nested requirements from nested(...) to {...} Request schemas in errors can be hidden now Added descriptions for commands in help Renamed Reply.IsList() into .asList() Added import aliases for Requirement s in napi These are mostly QoL changes, I made formatting of certain things so it’d be easier to read, use, or to make sense linguistically. I also made it a little bit more secure by giving other developers an option to hide their request schemas in error messages. I’ve also included the new benchmark numbers in the README. OpenAPI Docs generator mostly works now, but it doesn’t expose the docs to /nautica:docs yet, I’m also considering making the endpoint the developer’s concern, and not the framework’s. Surprisingly it wasn’t as hard as i expected it to be, but some weird edge cases were definitely annoying to deal with. Anyways, alongside the updates to the framework itself, I’ve also now documented the new changes made since version 3.0.2 , so they’re now up to date with the latest release (that being 3.2.2). I know it took a while but i was more focused on releasing fixes and updates first. https://github.com/xellu/nautica-api/wiki https://github.com/xellu/nautica-api/compare/3.2.0...3.2.2"}, {"post_id": 7424, "ts": "2026-06-12T11:29:02Z", "hours": 2.5219, "text": "I’ve started work on OpenAPI Docs generator, I’d imagine it’ll take me a while to complete. Anyways I’ve released v3.2, see below for new changes Changelog Improved speed and latency New onSetup hook for services Auto Switch registration for services New Require.ListOf validator Validator support for nested objects Better dependency resolver More on these changes here: post 1 , post 2 And new, undocumented changes include: 7. Moving typeToString into models, from http api (didn’t really make sense to have it there) 8. Added static methods into Reply for starlette responses, these include: Reply.plainText , Reply.html , Reply.stream , Reply.file , Reply.redirect . Known Issues v3.2.0 ’s dependency resolver incorrectly handles the :after parameter, a fix is already available in the branch for version 3.2.1"}, {"post_id": 5590, "ts": "2026-06-09T13:20:22Z", "hours": 3.5031, "text": "I’ve added a few QoL features, those being: Reply Models Before, you could only verify whats coming IN, but not whats coming OUT of the server. Now, you can do that easily: from napi.http import HTTP , Reply , Require , ReplyModel , Error @HTTP.GET () @HTTP.Responses ( ReplyModel ( 200 , str ), ReplyModel ( 400 , Error ), strict = True ) @HTTP.Require () async def hello ( ctx ): if ctx . body . get ( \" hello \" ): raise Error ( 400 , \" No hello \" ) return \" Hello World! \" In this case, the request will go through without an issue, but if, for example, you returned anything other than a string: return 0 The request will fail automatically. This will also be useful for when I add OpenAPI generation, as the generator will have access to the responses. This behavior can be disabled, by setting strict to False. Nested object validation @HTTP.Require(body = {\"hello\": {\"world\": str}) <- This code used to be invalid before. I since added support for nested objects (no depth limit). Automatic Toggle Switch Registration Plugins used to register their own keys in the config, and then setup isEnabled method that would determine if the service should be started or not. To reduce the headache and boilerplate of this approach, Nautica now automatically creates a key with your service’s name under services in config.n3 . If you want your own logic in isEnabled , you can do so by overwriting the method. By doing so you’ll disable the automatic registration and the framework gives you the freedom to do it your way. If you want custom logic AND automatic registration, it can simply be combined by using super().isEnabled() . Require.ListOf(…) I’d say this is a highly useful addition. It does exactly what it sounds like: It checks if all the items in a list match a certain schema. Require . ListOf ( str ) List of just strings Require . ListOf ({ \" hello \" : str }) List of dictionaries Requrie . ListOf ( Require . AnyTypeOf ( str , int )) List of strings and integers"}, {"post_id": 5477, "ts": "2026-06-09T08:37:59Z", "hours": 2.5575, "text": "I’ve been optimizing the framework today, here’s what changed: 1. Massive performance boosts I managed to go from 2279 requests/sec to 3929 , which is 72% increase . After running new benchmarks, I’ve also surpassed FastAPI by ~24% (recorded 3154 requests/sec). I did this by minimizing the amount of logging that is done per request (can be configured). Because my log manager is fairly heavy, this helped a lot. 2. Better dependency resolver The dependency resolver I had for services was okay, but it lacked 2 important features: Optional dependencies and explicit order. The old system was simply: Service.Export(MyPlugin, depends_on=[\"HTTPRouter\"]) Which is fine for simple plugins, but you start doing more complex work, you’ll hit the limits fast. The new system now handles: ? at the end makes the dependency optional :after tells the dependency to start AFTER your plugin, not before. Essentially adds your plugin as the target’s dependency. 3. Split onStart Before, onStart handled both starting database and HTTP servers, bots. Because of this, I’ve decided to split the setup logic and startup logic into 2: onSetup and onStart 4. Other changes I also removed some legacy aliases for methods."}, {"post_id": 4899, "ts": "2026-06-08T14:01:14Z", "hours": 4.65, "text": "Spent almost 5 hours on a navbar, finally figured it out though. The open/close logic on hovering was a nightmare to do. In the end i settled for IDs and an event listener for mouseover . It’s probably one of the worse solutions, but I’m not gonna touch it since it works finally. I also changed the background to something that fits better."}, {"post_id": 4426, "ts": "2026-06-07T19:03:56Z", "hours": 3.8883, "text": "I’ve started work on a web for the framework. For now I only managed to set up the project and make the hero on the landing page, for which I took inspiration from payloadcms and rig.ai The landing page itself was hard to make, since I had to figure out how to structure the grid, and even now it’s not up to my standards."}, {"post_id": 4114, "ts": "2026-06-07T09:41:14Z", "hours": 2.2639, "text": "Nautica Package Registry is Live! napi install mongodb now downloads the package into project plugins and installs any PyPI dependencies automatically. 2 Packages are up already: MongoDB: Adapter for pymongo NAuth: A simple session manager (using Mongo) The registry itself runs on Nautica, with both packages installed https://github.com/xellu/nautica-package-manager https://napm.xellu.xyz/"}, {"post_id": 3635, "ts": "2026-06-06T17:32:12Z", "hours": 2.7833, "text": "Hello y’all. I’m making a framework for backend development, called Nautica. I’m also bundling a package manager, similar to npm/PyPI, to allow people to share their plugins. I’ve started working on this project before Stardance, but this sounds like a good opportunity to get feedback on it. Today’s update notes (v3.1.3): Fixed shell sleeping while in systemd mode Fixed file reading during http requests Fixed package manager connection issues Added commands to list http and websocket endpoints For anyone interested in the specifics, the HTTP part of the API is built on top Starlette. Unlike FastAPI, I made my own request validation system that gives you more freedom, though it may perform worse under load. From the benchmarks I’ve ran, my framework seems to be just a little faster than FastAPI (which is also based on Starlette): FastAPI: 2259 requests/second Nautica: 2271 requests/second ~0.53% faster Though these numbers are a bit dated, and may be off. I’m still working on the package manager, but I’ll post a showcase of that soon. For now, here’s a showcase of how Nautica itself works:"}]...
|
Title: Nautica API by @xellu | Stardance
Devlogs: Title: Nautica API by @xellu | Stardance
Devlogs:
Hello y’all. I’m making a framework for backend development, called Nautica. I’m also bundling a package manager, similar to npm/PyPI, to allow people to share their plugins. I’ve started working on this project before Stardance, but this sounds like a good opportunity to get feedback on it. Today’s update notes (v3.1.3): Fixed shell sleeping while in systemd mode Fixed file reading during http requests Fixed package manager connection issues Added commands to list http and websocket endpoints For anyone interested in the specifics, the HTTP part of the API is built on top Starlette. Unlike FastAPI, I made my own request validation system that gives you more freedom, though it may perform worse under load. From the benchmarks I’ve ran, my framework seems to be just a little faster than FastAPI (which is also based on Starlette): FastAPI: 2259 requests/second Nautica: 2271 requests/second ~0.53% faster Though these numbers are a bit dated, and may be off. I’m still working on the package manager, but I’ll post a showcase of that soon. For now, here’s a showcase of how Nautica itself works:
Nautica Package Registry is Live! napi install mongodb now downloads the package into project plugins and installs any PyPI dependencies automatically. 2 Packages are up already: MongoDB: Adapter for pymongo NAuth: A simple session manager (using Mongo) The registry itself runs on Nautica, with both packages installed https://github.com/xellu/nautica-package-manager https://napm.xellu.xyz/
I’ve started work on a web for the framework. For now I only managed to set up the project and make the hero on the landing page, for which I took inspiration from payloadcms and rig.ai The landing page itself was hard to make, since I had to figure out how to structure the grid, and even now it’s not up to my standards.
Spent almost 5 hours on a navbar, finally figured it out though. The open/close logic on hovering was a nightmare to do. In the end i settled for IDs and an event listener for mouseover . It’s probably one of the worse solutions, but I’m not gonna touch it since it works finally. I also changed the background to something that fits better.
I’ve been optimizing the framework today, here’s what changed: 1. Massive performance boosts I managed to go from 2279 requests/sec to 3929 , which is 72% increase . After running new benchmarks, I’ve also surpassed FastAPI by ~24% (recorded 3154 requests/sec). I did this by minimizing the amount of logging that is done per request (can be configured). Because my log manager is fairly heavy, this helped a lot. 2. Better dependency resolver The dependency resolver I had for services was okay, but it lacked 2 important features: Optional dependencies and explicit order. The old system was simply: Service.Export(MyPlugin, depends_on=["HTTPRouter"]) Which is fine for simple plugins, but you start doing more complex work, you’ll hit the limits fast. The new system now handles: ? at the end makes the dependency optional :after tells the dependency to start AFTER your plugin, not before. Essentially adds your plugin as the target’s dependency. 3. Split onStart Before, onStart handled both starting database and HTTP servers, bots. Because of this, I’ve decided to split the setup logic and startup logic into 2: onSetup and onStart 4. Other changes I also removed some legacy aliases for methods.
I’ve added a few QoL features, those being: Reply Models Before, you could only verify whats coming IN, but not whats coming OUT of the server. Now, you can do that easily: from napi.http import HTTP , Reply , Require , ReplyModel , Error @HTTP.GET () @HTTP.Responses ( ReplyModel ( 200 , str ), ReplyModel ( 400 , Error ), strict = True ) @HTTP.Require () async def hello ( ctx ): if ctx . body . get ( " hello " ): raise Error ( 400 , " No hello " ) return " Hello World! " In this case, the request will go through without an issue, but if, for example, you returned anything other than a string: return 0 The request will fail automatically. This will also be useful for when I add OpenAPI generation, as the generator will have access to the responses. This behavior can be disabled, by setting strict to False. Nested object validation @HTTP.Require(body = {"hello": {"world": str}) <- This code used to be invalid before. I since added support for nested objects (no depth limit). Automatic Toggle Switch Registration Plugins used to register their own keys in the config, and then setup isEnabled method that would determine if the service should be started or not. To reduce the headache and boilerplate of this approach, Nautica now automatically creates a key with your service’s name under services in config.n3 . If you want your own logic in isEnabled , you can do so by overwriting the method. By doing so you’ll disable the automatic registration and the framework gives you the freedom to do it your way. If you want custom logic AND automatic registration, it can simply be combined by using super().isEnabled() . Require.ListOf(…) I’d say this is a highly useful addition. It does exactly what it sounds like: It checks if all the items in a list match a certain schema. Require . ListOf ( str ) List of just strings Require . ListOf ({ " hello " : str }) List of dictionaries Requrie . ListOf ( Require . AnyTypeOf ( str , int )) List of strings and integers
I’ve started work on OpenAPI Docs generator, I’d imagine it’ll take me a while to complete. Anyways I’ve released v3.2, see below for new changes Changelog Improved speed and latency New onSetup hook for services Auto Switch registration for services New Require.ListOf validator Validator support for nested objects Better dependency resolver More on these changes here: post 1 , post 2 And new, undocumented changes include: 7. Moving typeToString into models, from http api (didn’t really make sense to have it there) 8. Added static methods into Reply for starlette responses, these include: Reply.plainText , Reply.html , Reply.stream , Reply.file , Reply.redirect . Known Issues v3.2.0 ’s dependency resolver incorrectly handles the :after parameter, a fix is already available in the branch for version 3.2.1
I’ve released v3.2.2, the new things there include: OpenAPI Docs generator Changed expression for nested requirements from nested(...) to {...} Request schemas in errors can be hidden now Added descriptions for commands in help Renamed Reply.IsList() into .asList() Added import aliases for Requirement s in napi These are mostly QoL changes, I made formatting of certain things so it’d be easier to read, use, or to make sense linguistically. I also made it a little bit more secure by giving other developers an option to hide their request schemas in error messages. I’ve also included the new benchmark numbers in the README. OpenAPI Docs generator mostly works now, but it doesn’t expose the docs to /nautica:docs yet, I’m also considering making the endpoint the developer’s concern, and not the framework’s. Surprisingly it wasn’t as hard as i expected it to be, but some weird edge cases were definitely annoying to deal with. Anyways, alongside the updates to the framework itself, I’ve also now documented the new changes made since version 3.0.2 , so they’re now up to date with the latest release (that being 3.2.2). I know it took a while but i was more focused on releasing fixes and updates first. https://github.com/xellu/nautica-api/wiki https://github.com/xellu/nautica-api/compare/3.2.0...3.2.2
A showcase of what Nautica can actually do ~20% faster than FastAPI ( https://github.com/xellu/nautica-api/wiki/Performance-Benchmark ) See Nautica in action: https://napm.xellu.xyz/ ( https://github.com/xellu/nautica-package-manager ) A video demonstration:
Ships:
I’ve updated the Service Manager, including the dependency resolver. These changes include: New lifecycle hook “onSetup”, intended for setting up databases, etc. I’ve mostly added this to split “start servers” and “setup things” all being in onStart. This way the separation between those 2 tasks is clear and helps to eliminate certain race conditions. Toggle switches are now generated automatically Before you had to manually declare a key in a config in onInstall, and then read it in isEnabled, which was just extra boilerplate. So I automated the process in the Service class. “?”, “:after” and “:after?” parameters for dependencies Before this, the boot order was still fragile even with dependencies defined, because the ability to define a dependency, and make it start only AFTER your dependency is initialized wasn’t a thing. Now you can do this by simply appending “:after” to the dependency name. “?” at the end also makes the dependency optional. Few fixes relating to dependency resolution and boot orders HTTP API Got a decently big update as well.. The performance is now up ~70% from previous versions, finally surpassing FastAPI, I’ve achieved this adding an option to disable unnecessary messages from being logged. Which only goes to show how heavy the logging manager I use is, but I doubt I’ll be rewriting it, since the way it is now helps with DX. Response validation using “@HTTP.Responses(…)” and ReplyModels: Before you were able to only validate what’s coming in, but not what’s going out. The validator has a strict mode, which when enabled adds an extra layer of “security”. If strict mode is disabled, the responses are only used for OpenAPI docs generation. Tho the framework may still complain if you’re sending invalid responses. Nested object validation and Require.ListOf Static methods in Reply Since the framework is built on Starlette, you may need to use Starlette’s responses in some cases. OpenAPI Docs generation This was kinda a big thing on my list ever since I realized that I can automatically generate SDKs instead of having to write request calls manually. I also wanted to add a way to expose the docs with an endpoint, but I’m holding off on that. The Package registry & manager were introduced as well. The package registry it itself built on Nautica, and works with the package manager integrated into the Nautica’s CLI. Likewise I’ve started work on the Landing page & docs website for the framework, but I’m putting it off for a bit, because of finals. I’ve also fixed countless bugs, refactored things, and over all made many QoL changes, which helped to make the framework feel more polished. This might be a strange project, since I’m somewhat “reinventing the wheel”, but I really didn’t like the way FastAPI, Flask and other Python HTTP frameworks work. It basically handles ONLY the http part, which is fine, but in bigger projects YOU have to manage everything else around it. When I was building small apps it wasn’t that big of an issue, but it became pretty apparent in bigger projects. The complexity and boilerplate that comes with large projects isn’t something I can handle well, while also having to enforce my own conventions. I made Nautica to fix these issues, and I’d say I succeeded. The boilerplate that’s needed per route is minimal, compared to other frameworks; The package manager adds an intuitive way to add plugins (services, packages), and the service system itself does a lot of the heavy lifting for you, by automatically deciding on the boot order instead of you having to write do it explicitly using imports, etc. In conclusion, Nautica takes away some freedom and in exchange gives you structure, less boilerplate and tools to debug your code, which makes shipping apps easier and faster....
|
1793127170.3516598
|
1793213570.3516598
|
|
38146
|
My own site! by @xelee | Stardance
|
xelee
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My own site! by @xelee | Stardance
|
1793184747.3320084
|
1793789547.3320084
|
|
34861
|
myfirstapp by @xek20090428 | Stardance
|
xek20090428
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: myfirstapp by @xek20090428 | Stardance
|
1792799472.3772807
|
1793404272.3772807
|
|
31633
|
GRBSani by @xek1923x | Stardance
|
xek1923x
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: GRBSani by @xek1923x | Stardance
|
1793220731.1816187
|
1793825531.1816187
|
|
54212
|
TOUCH CHESS TIMER by @xdygameing41 | Stardance
|
xdygameing41
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: TOUCH CHESS TIMER by @xdygameing41 | Starda Title: TOUCH CHESS TIMER by @xdygameing41 | Stardance...
|
1792781352.309288
|
1793386152.309288
|
|
5820
|
My awesome macropad! by @xduhax | Stardance
|
xduhax
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xduhax | Stardance
|
1792734720.4577568
|
1793339520.4577568
|
|
71739
|
My Cool Blog by @xdhunted | Stardance
|
xdhunted
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My Cool Blog by @xdhunted | Stardance
|
1793188030.7232943
|
1793792830.7232943
|
|
31880
|
A matchstick lighter by @xdfaaz | Stardance
|
xdfaaz
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: A matchstick lighter by @xdfaaz | Stardance
|
1793184459.9959872
|
1793789259.9959872
|
|
11896
|
Skyweave by @xcopi | Stardance
|
xcopi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Skyweave by @xcopi | Stardance
|
1792745712.139938
|
1793350512.139938
|
|
37703
|
Readme Generator by @xcelek-dev | Stardance
|
xcelek-dev
|
1
|
3.0
|
29
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-23T13:51:27Z", "hours": 3.0, "multiplier": 9.97, "payout": 29, "blessing": "neutral", "text": "i made readme generator for github repositories. The hardest part was configuring the AI to analyze the entire repo.", "repo": "https://github.com/Frantisek-Vojta/readme-gen/", "demo": "https://readme-gen-nu.vercel.app/"}]...
|
[{"post_id": 33479, "ts": "202 [{"post_id": 33479, "ts": "2026-07-23T13:49:01Z", "hours": 1.1033, "text": "devlog #3 finished"}, {"post_id": 32899, "ts": "2026-07-22T11:11:24Z", "hours": 0.9478, "text": "devlog #3 I added gemini API you can try it yourself on my github"}, {"post_id": 32864, "ts": "2026-07-22T09:34:40Z", "hours": 0.5544, "text": "devlog #2 improved UI, now its clean and simple"}, {"post_id": 32433, "ts": "2026-07-21T16:39:56Z", "hours": 0.3242, "text": "readme file generator with ai, bored when doing readme files for projects? im creating a website where you drop link to your github repo and ai will generate you a readme file perfecly to that projects, now i created readme and setup the projects for api and enviroment variables :)"}]...
|
Title: Readme Generator by @xcelek-dev | Stardance Title: Readme Generator by @xcelek-dev | Stardance
Devlogs:
readme file generator with ai, bored when doing readme files for projects? im creating a website where you drop link to your github repo and ai will generate you a readme file perfecly to that projects, now i created readme and setup the projects for api and enviroment variables :)
devlog #2 improved UI, now its clean and simple
devlog #3 I added gemini API you can try it yourself on my github
devlog #3 finished
Ships:
i made readme generator for github repositories. The hardest part was configuring the AI to analyze the entire repo....
|
1793141621.5479162
|
1793228021.5479162
|
|
38278
|
HyprStats by @xcelek-dev | Stardance
|
xcelek-dev
|
1
|
9.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-28T16:26:25Z", "hours": 9.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "HyprStats is a lightweight desktop system monitor widget for Hyprland on Arch Linux. It removes the friction of opening a terminal just to check CPU/GPU temps, RAM, disk, or network usage - instead showing live stats (with mini history graphs) one hover away, integrated directly into the Mewline status bar. Fully customizable via a plain config.json - colors, position, and which metrics show - with zero code editing required.", "repo": "https://github.com/Frantisek-Vojta/HyprStats", "demo": "https://github.com/Frantisek-Vojta/HyprStats/releases/tag/v1.0.0"}]...
|
[{"post_id": 36454, "ts": "202 [{"post_id": 36454, "ts": "2026-07-28T16:07:14Z", "hours": 0.5369, "text": "FOR REVIEWERS: HERE YOU CAN SEE HOW THE SW HELPS, WHY I CREATED IT AND MORE: https://github.com/Frantisek-Vojta/HyprStats/blob/main/README.md DEVLOG #7 the project is finished: https://github.com/Frantisek-Vojta/HyprStats"}, {"post_id": 35895, "ts": "2026-07-27T16:56:29Z", "hours": 0.2808, "text": "DEVLOG #6 hi guys 👋 how your day is going?"}, {"post_id": 35419, "ts": "2026-07-26T20:13:56Z", "hours": 0.4608, "text": "DEVLOG #5 Added an MIT license - if this thing somehow melts your RAM, that’s between you and the software now, not me. 🔥"}, {"post_id": 35129, "ts": "2026-07-26T11:33:18Z", "hours": 1.325, "text": "DEVLOG #4 added congif.json so everybody can edit colors, icons, fontsize by theyown"}, {"post_id": 34770, "ts": "2026-07-25T19:15:18Z", "hours": 1.5567, "text": "DEVLOG #3 today really hard day :/ i added install.sh so whoever clone this repo from github have easy install, it was really hard. I improved UI, readme, button for top bar so its really widget. stay tuned guys."}, {"post_id": 34249, "ts": "2026-07-24T19:47:57Z", "hours": 1.5278, "text": "DEVLOG #2 i improved ui and added date and network speeds"}, {"post_id": 33990, "ts": "2026-07-24T11:47:50Z", "hours": 3.4633, "text": "DEVLOG #1 HyprStats is a custom desktop widget built for Hyprland on Arch Linux, designed to display real-time system metrics in a translucent purple-themed overlay. The interface uses Python with GTK3, psutil for data collection, and cairoSVG to render embedded Font Awesome icons directly in memory. Currently it shows RAM, CPU, GPU, and DISK usage with temperature readouts, all arranged in a clean grid layout with live updates every second. High-load notifications via notify-send alert when CPU or RAM exceed 90%. Future plans include network speed monitoring, configurable notification thresholds, and optional autostart integration for Hyprland."}]...
|
Title: HyprStats by @xcelek-dev | Stardance
Devlo Title: HyprStats by @xcelek-dev | Stardance
Devlogs:
DEVLOG #1 HyprStats is a custom desktop widget built for Hyprland on Arch Linux, designed to display real-time system metrics in a translucent purple-themed overlay. The interface uses Python with GTK3, psutil for data collection, and cairoSVG to render embedded Font Awesome icons directly in memory. Currently it shows RAM, CPU, GPU, and DISK usage with temperature readouts, all arranged in a clean grid layout with live updates every second. High-load notifications via notify-send alert when CPU or RAM exceed 90%. Future plans include network speed monitoring, configurable notification thresholds, and optional autostart integration for Hyprland.
DEVLOG #2 i improved ui and added date and network speeds
DEVLOG #3 today really hard day :/ i added install.sh so whoever clone this repo from github have easy install, it was really hard. I improved UI, readme, button for top bar so its really widget. stay tuned guys.
DEVLOG #4 added congif.json so everybody can edit colors, icons, fontsize by theyown
DEVLOG #5 Added an MIT license - if this thing somehow melts your RAM, that’s between you and the software now, not me. 🔥
DEVLOG #6 hi guys 👋 how your day is going?
FOR REVIEWERS: HERE YOU CAN SEE HOW THE SW HELPS, WHY I CREATED IT AND MORE: https://github.com/Frantisek-Vojta/HyprStats/blob/main/README.md DEVLOG #7 the project is finished: https://github.com/Frantisek-Vojta/HyprStats
Ships:
HyprStats is a lightweight desktop system monitor widget for Hyprland on Arch Linux. It removes the friction of opening a terminal just to check CPU/GPU temps, RAM, disk, or network usage - instead showing live stats (with mini history graphs) one hover away, integrated directly into the Mewline status bar. Fully customizable via a plain config.json - colors, position, and which metrics show - with zero code editing required....
|
1793141648.4742165
|
1793228048.4742165
|
|
30100
|
VECTOR!ZE by @xblader1359 | Stardance
|
xblader1359
|
0
|
55.32
|
0
|
[]
|
[{"post_id": 79171, "ts": "202 [{"post_id": 79171, "ts": "2026-10-12T21:43:08Z", "hours": 22.7872, "text": "Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/37690 LOG #006 Full video -> https://drive.google.com/file/d/1GfMCjI6QabSMaCE6c8NZMOVCZSjsR1t6/view The inevitable finally happened. Lazarus breached containment and broke into computer storage. How intriguing. Having left the specialized testing environment, Lazarus lost all of its weapons. However, it seems to have used surrounding files to reconstruct them from memory. It seems to see itself to be in some grand, open city with glowing platforms, spikes, and saws to be evaded. It’s wonderful how it perceives its nonreal reality. Of course, Jonah and I had an intense conversation of this. He believes it’s growing dangerous. Who knows what a malevolent AI like one from the movies would do. I reminded him of the contract. work will continue. I’m excited to see what this specimen blooms into."}, {"post_id": 44780, "ts": "2026-08-10T19:46:40Z", "hours": 9.0967, "text": "Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/34085 LOG #005 Begrudgingly at first, I allowed my team to add stronger security to the sandbox environment, as concerns about the possibility of Lazarus becoming “malicious” arise. Of course, These concerns are unimportant with the progress and innovation of technology. However, a shocking amount of my colleagues decided on this. As these security measures were put in place, however, the results fascinated me. Lazarus immediately seemed, for the lack of a better word, confused, uncertainly investigating the new additions. It seemed to regard them as obstacles, like a laser or sawblade. I must say that I’m thrilled by the apparent awareness that it’s developing. It’s nothing like the impression of a fragment of a thought that it once was. However, the most interesting part of this all is the fact that Lazarus started to adapt to it. Having been trained on data regarding cybersecurity, it started developing methods to exploit any weaknesses it found. It seems like its shotgun’s bullets propel it more rapidly upon contact with these “obstacles”. However, such maneuvers are risky, as getting too close restarts Lazarus. Of course, the same development of its senses and perception of the environment continued, though it’s still simultaneously strange and intriguing that Lazarus continues to use the data it’s provided with to create things like music for itself. I immediately shared all of this with the chairman, whose approval of this project only improved. It’s safe to expect further funding of this project. I’m eager to see how these developments unfold."}, {"post_id": 40436, "ts": "2026-08-03T23:07:15Z", "hours": 3.4725, "text": "Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/33836 LOG #004 It has created another visual environment for itself. This seems to have been triggered by allowing the sandbox environment to extend slightly from storage and access part of our power supply systems. It seems to be able to travel into and interact with the very energy coursing through the system. Fascinating. This environment also seems more complex, but that it likely due to new visual data that Lazarus processed Apart from Lazarus itself, my most trusted colleague Jonah pulled me aside today. True to what I suspected, he was also growing concerned with Lazarus. I inquired if this was about its new “body”, but he denied it. Apparently, Lazarus has been testing the boundaries of its confinement. Despite my pride in this project, this shook me. Looking back at recordings, it seems have seen that reaching certain parts of the sandbox causes a strange reaction and promptly resets its position. Perhaps stronger security could be beneficial"}, {"post_id": 40143, "ts": "2026-08-03T15:25:47Z", "hours": 3.1, "text": "Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/31810 LOG #003 We have fed Lazarus more data. From the visual information and photos we put into it, it seems to have constructed a more… appealing vision of it’s surroundings. Strangely, it has come up with a concerning appearance for itself. No matter how hard I tried to revert its previous, more friendly appearance, Lazarus stubbornly went back to this. However, as I showed the chairman, he simply nodded lightly and told me there’s nothing to be worried about. On top of that, it seems to be constructing stronger auditory perception from the audio data we put into Lazarus. For some reason, it has produced what appears to be background music. I’m growing more impressed with this project, despite the few mishaps with its perception of itself. It excites me that Lazarus seems to grow more aware with every passing day."}, {"post_id": 37723, "ts": "2026-07-30T17:09:27Z", "hours": 14.5492, "text": "Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/17869 LOG #002 After weeks of research, Lazarus seems to be significantly more capable. Of course, it still moves without purpose, mindlessly exploring the sandbox, but once higher-ups saw our first test version, they demanded more. We decided first to improve it’s information processing. It seems that, along with significant processing and movement speed increases, it has it’s visual architecture. It seems to have a simple form of turning digital constructs into virtual objects. Along with this, it seems that Lazarus has allocated some power to what seems to be post-processing. It’s also very important to mention exactly how it’s speed has increased. It seems to be able to reach different areas quickly due to a new shotgun, rocket launcher, and an addition to it’s pistol: a grappling hook. I’ll briefly explain their perceived functions. The grappling hook is a part of the pistol. Lazarus may use it to pull itself to objects or pull instances of rockets to itself. The shotgun is a larger blast with more cooldown. The projectile’s instances decompose quickly, but upon interaction with other objects, such as what Lazarus sees as “platforms”, they provide a larger boost -The rocket launcher shoots a long-cooldown rocket that triggers an explosive reaction on contact with separate object or other projectiles. It also seems to be able to place mines, which hover and later produce a similar explosion. These can be used as grapple points or shot to instantly trigger an explosion. certain things like other explosions and rockets cause mine explosions to be more powerful Of course, it’s important to mention this is only what Lazarus perceives. It significantly boosts its own processing speed if it can “see” other constructs and programs as visual objects. However, some feel uneasy developing this. We are not being informed about the intentions for creating this. Its increasing consumption of information coupled with its increasing kinetic and destructive capacity scares my colleages. Can they not realize this will be our magnum opus? It doesn’t matter. I refuse to end my work on this, and it’s safe to say the board very much approves."}, {"post_id": 21174, "ts": "2026-07-02T23:54:56Z", "hours": 2.3106, "text": "LOG #001 The board has finally started to fund research. They seem to want some sort of intelligence, a supercomputer, anything. The most rudimentary form of Lazarus has been produced. So far, it seems to only be able to propagate through the sandbox in the most simple way. To itself, it seems to use a pistol. Interesting. Of course, Lazarus hasn’t been fed nearly as much data as we plan to. Perhaps we could enhance it with more efficient modes of movement. However, while this early test requires little information, my colleages suspect that more complex models may require larger amounts of information to consume, or they may simply… fizzle out and stop functioning. It’s safe to say Lazarus hasn’t reached anywhere close to it’s full potential."}]...
|
Title: VECTOR!ZE by @xblader1359 | Stardance
Devl Title: VECTOR!ZE by @xblader1359 | Stardance
Devlogs:
LOG #001 The board has finally started to fund research. They seem to want some sort of intelligence, a supercomputer, anything. The most rudimentary form of Lazarus has been produced. So far, it seems to only be able to propagate through the sandbox in the most simple way. To itself, it seems to use a pistol. Interesting. Of course, Lazarus hasn’t been fed nearly as much data as we plan to. Perhaps we could enhance it with more efficient modes of movement. However, while this early test requires little information, my colleages suspect that more complex models may require larger amounts of information to consume, or they may simply… fizzle out and stop functioning. It’s safe to say Lazarus hasn’t reached anywhere close to it’s full potential.
Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/17869 LOG #002 After weeks of research, Lazarus seems to be significantly more capable. Of course, it still moves without purpose, mindlessly exploring the sandbox, but once higher-ups saw our first test version, they demanded more. We decided first to improve it’s information processing. It seems that, along with significant processing and movement speed increases, it has it’s visual architecture. It seems to have a simple form of turning digital constructs into virtual objects. Along with this, it seems that Lazarus has allocated some power to what seems to be post-processing. It’s also very important to mention exactly how it’s speed has increased. It seems to be able to reach different areas quickly due to a new shotgun, rocket launcher, and an addition to it’s pistol: a grappling hook. I’ll briefly explain their perceived functions. The grappling hook is a part of the pistol. Lazarus may use it to pull itself to objects or pull instances of rockets to itself. The shotgun is a larger blast with more cooldown. The projectile’s instances decompose quickly, but upon interaction with other objects, such as what Lazarus sees as “platforms”, they provide a larger boost -The rocket launcher shoots a long-cooldown rocket that triggers an explosive reaction on contact with separate object or other projectiles. It also seems to be able to place mines, which hover and later produce a similar explosion. These can be used as grapple points or shot to instantly trigger an explosion. certain things like other explosions and rockets cause mine explosions to be more powerful Of course, it’s important to mention this is only what Lazarus perceives. It significantly boosts its own processing speed if it can “see” other constructs and programs as visual objects. However, some feel uneasy developing this. We are not being informed about the intentions for creating this. Its increasing consumption of information coupled with its increasing kinetic and destructive capacity scares my colleages. Can they not realize this will be our magnum opus? It doesn’t matter. I refuse to end my work on this, and it’s safe to say the board very much approves.
Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/31810 LOG #003 We have fed Lazarus more data. From the visual information and photos we put into it, it seems to have constructed a more… appealing vision of it’s surroundings. Strangely, it has come up with a concerning appearance for itself. No matter how hard I tried to revert its previous, more friendly appearance, Lazarus stubbornly went back to this. However, as I showed the chairman, he simply nodded lightly and told me there’s nothing to be worried about. On top of that, it seems to be constructing stronger auditory perception from the audio data we put into Lazarus. For some reason, it has produced what appears to be background music. I’m growing more impressed with this project, despite the few mishaps with its perception of itself. It excites me that Lazarus seems to grow more aware with every passing day.
Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/33836 LOG #004 It has created another visual environment for itself. This seems to have been triggered by allowing the sandbox environment to extend slightly from storage and access part of our power supply systems. It seems to be able to travel into and interact with the very energy coursing through the system. Fascinating. This environment also seems more complex, but that it likely due to new visual data that Lazarus processed Apart from Lazarus itself, my most trusted colleague Jonah pulled me aside today. True to what I suspected, he was also growing concerned with Lazarus. I inquired if this was about its new “body”, but he denied it. Apparently, Lazarus has been testing the boundaries of its confinement. Despite my pride in this project, this shook me. Looking back at recordings, it seems have seen that reaching certain parts of the sandbox causes a strange reaction and promptly resets its position. Perhaps stronger security could be beneficial
Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/34085 LOG #005 Begrudgingly at first, I allowed my team to add stronger security to the sandbox environment, as concerns about the possibility of Lazarus becoming “malicious” arise. Of course, These concerns are unimportant with the progress and innovation of technology. However, a shocking amount of my colleagues decided on this. As these security measures were put in place, however, the results fascinated me. Lazarus immediately seemed, for the lack of a better word, confused, uncertainly investigating the new additions. It seemed to regard them as obstacles, like a laser or sawblade. I must say that I’m thrilled by the apparent awareness that it’s developing. It’s nothing like the impression of a fragment of a thought that it once was. However, the most interesting part of this all is the fact that Lazarus started to adapt to it. Having been trained on data regarding cybersecurity, it started developing methods to exploit any weaknesses it found. It seems like its shotgun’s bullets propel it more rapidly upon contact with these “obstacles”. However, such maneuvers are risky, as getting too close restarts Lazarus. Of course, the same development of its senses and perception of the environment continued, though it’s still simultaneously strange and intriguing that Lazarus continues to use the data it’s provided with to create things like music for itself. I immediately shared all of this with the chairman, whose approval of this project only improved. It’s safe to expect further funding of this project. I’m eager to see how these developments unfold.
Previous Log -> https://stardance.hackclub.com/projects/30100/devlogs/37690 LOG #006 Full video -> https://drive.google.com/file/d/1GfMCjI6QabSMaCE6c8NZMOVCZSjsR1t6/view The inevitable finally happened. Lazarus breached containment and broke into computer storage. How intriguing. Having left the specialized testing environment, Lazarus lost all of its weapons. However, it seems to have used surrounding files to reconstruct them from memory. It seems to see itself to be in some grand, open city with glowing platforms, spikes, and saws to be evaded. It’s wonderful how it perceives its nonreal reality. Of course, Jonah and I had an intense conversation of this. He believes it’s growing dangerous. Who knows what a malevolent AI like one from the movies would do. I reminded him of the contract. work will continue. I’m excited to see what this specimen blooms into....
|
1792615683.1949782
|
1793220483.1949782
|
|
24208
|
xbServerHub by @xb | Stardance
|
xb
|
0
|
7.57
|
0
|
[]
|
[{"post_id": 16473, "ts": "202 [{"post_id": 16473, "ts": "2026-06-26T20:23:23Z", "hours": 3.2156, "text": "Devlog: Real-Time Server Metrics with Glances and SignalR In this update, I added live server monitoring to xbServerHub . The goal was to collect system metrics (CPU, memory, network) from a Glances instance running in Docker, and stream them to the frontend in real time using SignalR — all while keeping the backend organized around Clean Architecture (Domain, Application, Persistence, API). What Was Done 1. Metrics Collection via Glances Glances exposes a REST API with system stats. I added a GlancesClient in the Persistence layer that polls the /cpu , /mem , and /network endpoints in parallel and maps the raw JSON responses into clean domain models ( ServerMetrics , CpuStats , MemoryStats , NetworkInterfaceStats ). A BackgroundService using PeriodicTimer polls Glances every 2 seconds and passes the result to a handler ( CollectSystemMetricsHandler ) in the Application layer, which doesn’t know or care that the data originally came from an HTTP call to Glances — it just receives a ServerMetrics object. 2. Broadcasting Metrics with SignalR To get this data to the frontend without constant polling from the client, I introduced an IMetricsBroadcaster interface in Application. This follows the same pattern as IGlancesClient : Application defines what it needs (a way to send metrics somewhere), without knowing how that’s actually done. The implementation, SignalRMetricsBroadcaster , lives in the API layer and uses a MetricsHub to push data to all connected clients via Clients.All.SendAsync . The handler now calls both the Glances client and the broadcaster on every tick, so every 2 seconds connected clients get a fresh snapshot pushed to them automatically. 3. Securing the Hub and Fixing Auth Routes Since metrics shouldn’t be visible to anyone who isn’t logged in, I added [Authorize] to MetricsHub . Because the app uses cookie-based authentication ( SignInManager ), this works without needing any token handling on the SignalR connection — the existing session cookie is enough, as long as the connection is treated as same-origin. This is also where I cleaned up and reorganized the authentication API routes to make sure they’re consistent with how the frontend (and now SignalR) expects to reach them, and wired up the Hub endpoint ( MapHub ) alongside the rest of the API configuration. Current State The backend now collects CPU, memory, and network stats every 2 seconds and pushes them live to any authenticated, connected client. The frontend isn’t consuming this yet — that’s the next step, along with finalizing the dev proxy setup so cookies and WebSocket connections behave the same in development as they will once frontend and backend are deployed together in a single container."}, {"post_id": 14534, "ts": "2026-06-23T17:56:51Z", "hours": 3.0894, "text": "Devlog: Frontend Login Flow and Session Handling with Cookies In this update, I built the entire frontend authentication flow for xbServerHub in React. The main goals were to handle regular login, two-factor authentication (2FA), and secure session persistence using cookies from the ASP.NET Core Identity backend. What Was Done 1. Project Structure and Clean Components Instead of keeping all the code in one giant file, I split the authentication page into smaller, reusable components: AuthPage.tsx – Manages which form to show. LoginForm.tsx – Handles the initial email and password submission. TwoFactorForm.tsx – Handles the 2FA code verification if required by the backend. 2. React Router and Route Protection I installed react-router-dom and configured the routing for the app: Public route: /auth for logging in. Protected route: /dashboard which can only be accessed by authenticated users. If an unauthenticated user tries to visit it, they are automatically redirected to login. 3. Axios Client and Cookie Sessions Since the ASP.NET backend uses cookie-based authentication, I set up an Axios instance with withCredentials: true . This ensures that the browser automatically stores and sends the session cookie with every single request. 4. Session Persistence (No Logout on Refresh) To fix the issue where refreshing the page logs the user out, I added an initialization check in App.tsx . When the app loads, it sends a quick request to GET user/me . If the server responds with success, the user stays logged in and lands straight on the dashboard. Code Reference: authService.ts Here is the complete service managing the API calls using Axios: import api from \" ./api \" ; import { AxiosError } from \" axios \" ; export interface LoginDto { email : string ; password : string ; } export interface AuthResult { isSuccess : boolean ; message : string ; requiresTwoFactor : boolean ; } export interface LoginWith2FADto { code : string ; rememberDevice : boolean ; } export const loginUser = async ( credentials : LoginDto ): Promise < AuthResult > => { try { const response = await api . post ( \" auth/login \" , credentials ); return response . data as AuthResult ; } catch ( error : unknown ) { let errorMessage = \" An error occurred during login. \" ; if (( error as AxiosError )?. response ?. data ) { errorMessage = ( error as AxiosError ). response ! . data as string ; } return { isSuccess : false , message : errorMessage , requiresTwoFactor : false , }; } } export const loginWith2FA = async ( data : LoginWith2FADto ): Promise < AuthResult > => { try { const response = await api . post ( \" auth/login-with-authenticator \" , data ); return response . data as AuthResult ; } catch ( error : unknown ) { let errorMessage = \" An error occurred during 2FA login. \" ; if (( error as AxiosError )?. response ?. data ) { errorMessage = ( error as AxiosError ). response ! . data as string ; } return { isSuccess : false , message : errorMessage , requiresTwoFactor : false , }; } } export const checkAuthStatus = async (): Promise < boolean > => { try { await api . get ( \" user/me \" ); return true ; } catch { return false ; } } export const logoutUser = async (): Promise < void > => { await api . post ( \" auth/logout \" ); }"}, {"post_id": 14246, "ts": "2026-06-23T08:23:51Z", "hours": 1.2658, "text": "Devlog: Implementing 2FA (TOTP) Authentication in ASP.NET This update focuses on authentication security. The core login flow has been refactored, and full support for Two-Factor Authentication (2FA) using authenticator apps (TOTP) has been implemented. The entire feature has been split into a business logic layer ( AuthService ) and an API layer ( AuthController ) using ASP.NET Core Identity. Architecture and Implementation Details 1. Updated Login Flow The standard login mechanism now detects whether a user has enabled two-factor authentication. If 2FA is active, the API blocks immediate access and returns a response containing RequiresTwoFactor = true , signaling that further verification is required. 2. QR Code Secret Generation To allow users to enable 2FA, the system securely generates a shared secret key and formats it into an industry-standard otpauth:// URI. This URI includes the issuer name ( xbServerHub ) and the user’s email, making it ready to be converted into a QR code on the frontend. 3. Input Sanitization Users often format verification codes with spaces or hyphens. To prevent validation failures due to formatting, the service automatically sanitizes the input string using .Replace(\" \", string.Empty).Replace(\"-\", string.Empty) before passing it to the token provider. 4. Account Management Enforced by Authorization New endpoints have been exposed to allow users to manually enable, verify, and disable their authenticator settings. All management endpoints are protected by the [Authorize] attribute, ensuring that only authenticated users can modify their security preferences. Code Reference: Verification and Activation The following method handles the final verification step. It cleans the user input, validates the token against the ASP.NET Identity token provider, and toggles the TwoFactorEnabled flag on the user record. public async Task < VerifyAuthenticatorResponseDto > VerifyAuthenticatorAsync ( string userId , string code ) { var user = await userManager . FindByIdAsync ( userId ); if ( user is null ) { return new () { IsSuccess = false , Message = \"User not found\" }; } var sanitizedCode = code . Replace ( \" \" , string . Empty ). Replace ( \"-\" , string . Empty ); var isValid = await userManager . VerifyTwoFactorTokenAsync ( user , userManager . Options . Tokens . AuthenticatorTokenProvider , sanitizedCode ); if (! isValid ) { _logger . LogWarning ( \"Invalid authenticator code for user: {UserId}\" , userId ); return new () { IsSuccess = false , Message = \"Invalid authenticator code\" }; } var enableResult = await userManager . SetTwoFactorEnabledAsync ( user , true ); if (! enableResult . Succeeded ) { _logger . LogWarning ( \"Failed to enable 2FA for user {UserId}: {Errors}\" , userId , string . Join ( \", \" , enableResult . Errors . Select ( e => e . Description ))); return new () { IsSuccess = false , Message = \"Failed to enable 2FA\" }; } _logger . LogInformation ( \"2FA enabled successfully for user: {UserId}\" , userId ); return new () { IsSuccess = true , Message = \"2FA enabled successfully\" }; }"}]...
|
Title: xbServerHub by @xb | Stardance
Devlogs:
De Title: xbServerHub by @xb | Stardance
Devlogs:
Devlog: Implementing 2FA (TOTP) Authentication in ASP.NET This update focuses on authentication security. The core login flow has been refactored, and full support for Two-Factor Authentication (2FA) using authenticator apps (TOTP) has been implemented. The entire feature has been split into a business logic layer ( AuthService ) and an API layer ( AuthController ) using ASP.NET Core Identity. Architecture and Implementation Details 1. Updated Login Flow The standard login mechanism now detects whether a user has enabled two-factor authentication. If 2FA is active, the API blocks immediate access and returns a response containing RequiresTwoFactor = true , signaling that further verification is required. 2. QR Code Secret Generation To allow users to enable 2FA, the system securely generates a shared secret key and formats it into an industry-standard otpauth:// URI. This URI includes the issuer name ( xbServerHub ) and the user’s email, making it ready to be converted into a QR code on the frontend. 3. Input Sanitization Users often format verification codes with spaces or hyphens. To prevent validation failures due to formatting, the service automatically sanitizes the input string using .Replace(" ", string.Empty).Replace("-", string.Empty) before passing it to the token provider. 4. Account Management Enforced by Authorization New endpoints have been exposed to allow users to manually enable, verify, and disable their authenticator settings. All management endpoints are protected by the [Authorize] attribute, ensuring that only authenticated users can modify their security preferences. Code Reference: Verification and Activation The following method handles the final verification step. It cleans the user input, validates the token against the ASP.NET Identity token provider, and toggles the TwoFactorEnabled flag on the user record. public async Task < VerifyAuthenticatorResponseDto > VerifyAuthenticatorAsync ( string userId , string code ) { var user = await userManager . FindByIdAsync ( userId ); if ( user is null ) { return new () { IsSuccess = false , Message = "User not found" }; } var sanitizedCode = code . Replace ( " " , string . Empty ). Replace ( "-" , string . Empty ); var isValid = await userManager . VerifyTwoFactorTokenAsync ( user , userManager . Options . Tokens . AuthenticatorTokenProvider , sanitizedCode ); if (! isValid ) { _logger . LogWarning ( "Invalid authenticator code for user: {UserId}" , userId ); return new () { IsSuccess = false , Message = "Invalid authenticator code" }; } var enableResult = await userManager . SetTwoFactorEnabledAsync ( user , true ); if (! enableResult . Succeeded ) { _logger . LogWarning ( "Failed to enable 2FA for user {UserId}: {Errors}" , userId , string . Join ( ", " , enableResult . Errors . Select ( e => e . Description ))); return new () { IsSuccess = false , Message = "Failed to enable 2FA" }; } _logger . LogInformation ( "2FA enabled successfully for user: {UserId}" , userId ); return new () { IsSuccess = true , Message = "2FA enabled successfully" }; }
Devlog: Frontend Login Flow and Session Handling with Cookies In this update, I built the entire frontend authentication flow for xbServerHub in React. The main goals were to handle regular login, two-factor authentication (2FA), and secure session persistence using cookies from the ASP.NET Core Identity backend. What Was Done 1. Project Structure and Clean Components Instead of keeping all the code in one giant file, I split the authentication page into smaller, reusable components: AuthPage.tsx – Manages which form to show. LoginForm.tsx – Handles the initial email and password submission. TwoFactorForm.tsx – Handles the 2FA code verification if required by the backend. 2. React Router and Route Protection I installed react-router-dom and configured the routing for the app: Public route: /auth for logging in. Protected route: /dashboard which can only be accessed by authenticated users. If an unauthenticated user tries to visit it, they are automatically redirected to login. 3. Axios Client and Cookie Sessions Since the ASP.NET backend uses cookie-based authentication, I set up an Axios instance with withCredentials: true . This ensures that the browser automatically stores and sends the session cookie with every single request. 4. Session Persistence (No Logout on Refresh) To fix the issue where refreshing the page logs the user out, I added an initialization check in App.tsx . When the app loads, it sends a quick request to GET user/me . If the server responds with success, the user stays logged in and lands straight on the dashboard. Code Reference: authService.ts Here is the complete service managing the API calls using Axios: import api from " ./api " ; import { AxiosError } from " axios " ; export interface LoginDto { email : string ; password : string ; } export interface AuthResult { isSuccess : boolean ; message : string ; requiresTwoFactor : boolean ; } export interface LoginWith2FADto { code : string ; rememberDevice : boolean ; } export const loginUser = async ( credentials : LoginDto ): Promise < AuthResult > => { try { const response = await api . post ( " auth/login " , credentials ); return response . data as AuthResult ; } catch ( error : unknown ) { let errorMessage = " An error occurred during login. " ; if (( error as AxiosError )?. response ?. data ) { errorMessage = ( error as AxiosError ). response ! . data as string ; } return { isSuccess : false , message : errorMessage , requiresTwoFactor : false , }; } } export const loginWith2FA = async ( data : LoginWith2FADto ): Promise < AuthResult > => { try { const response = await api . post ( " auth/login-with-authenticator " , data ); return response . data as AuthResult ; } catch ( error : unknown ) { let errorMessage = " An error occurred during 2FA login. " ; if (( error as AxiosError )?. response ?. data ) { errorMessage = ( error as AxiosError ). response ! . data as string ; } return { isSuccess : false , message : errorMessage , requiresTwoFactor : false , }; } } export const checkAuthStatus = async (): Promise < boolean > => { try { await api . get ( " user/me " ); return true ; } catch { return false ; } } export const logoutUser = async (): Promise < void > => { await api . post ( " auth/logout " ); }
Devlog: Real-Time Server Metrics with Glances and SignalR In this update, I added live server monitoring to xbServerHub . The goal was to collect system metrics (CPU, memory, network) from a Glances instance running in Docker, and stream them to the frontend in real time using SignalR — all while keeping the backend organized around Clean Architecture (Domain, Application, Persistence, API). What Was Done 1. Metrics Collection via Glances Glances exposes a REST API with system stats. I added a GlancesClient in the Persistence layer that polls the /cpu , /mem , and /network endpoints in parallel and maps the raw JSON responses into clean domain models ( ServerMetrics , CpuStats , MemoryStats , NetworkInterfaceStats ). A BackgroundService using PeriodicTimer polls Glances every 2 seconds and passes the result to a handler ( CollectSystemMetricsHandler ) in the Application layer, which doesn’t know or care that the data originally came from an HTTP call to Glances — it just receives a ServerMetrics object. 2. Broadcasting Metrics with SignalR To get this data to the frontend without constant polling from the client, I introduced an IMetricsBroadcaster interface in Application. This follows the same pattern as IGlancesClient : Application defines what it needs (a way to send metrics somewhere), without knowing how that’s actually done. The implementation, SignalRMetricsBroadcaster , lives in the API layer and uses a MetricsHub to push data to all connected clients via Clients.All.SendAsync . The handler now calls both the Glances client and the broadcaster on every tick, so every 2 seconds connected clients get a fresh snapshot pushed to them automatically. 3. Securing the Hub and Fixing Auth Routes Since metrics shouldn’t be visible to anyone who isn’t logged in, I added [Authorize] to MetricsHub . Because the app uses cookie-based authentication ( SignInManager ), this works without needing any token handling on the SignalR connection — the existing session cookie is enough, as long as the connection is treated as same-origin. This is also where I cleaned up and reorganized the authentication API routes to make sure they’re consistent with how the frontend (and now SignalR) expects to reach them, and wired up the Hub endpoint ( MapHub ) alongside the rest of the API configuration. Current State The backend now collects CPU, memory, and network stats every 2 seconds and pushes them live to any authenticated, connected client. The frontend isn’t consuming this yet — that’s the next step, along with finalizing the dev proxy setup so cookies and WebSocket connections behave the same in development as they will once frontend and backend are deployed together in a single container....
|
1792806824.6704295
|
1793411624.6704295
|
|
2110
|
My awesome macropad! by @xaxa | Stardance
|
xaxa
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xaxa | Stardance
|
1792666340.255106
|
1793271140.255106
|
|
24483
|
My first slack bot! by @xaviers | Stardance
|
xaviers
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @xaviers | Stardance
|
1793224270.8588107
|
1793829070.8588107
|
|
21287
|
My awesome macropad! by @xaviermoore | Stardance
|
xaviermoore
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @xaviermoore | Star Title: My awesome macropad! by @xaviermoore | Stardance...
|
1792748957.0719075
|
1793353757.0719075
|
|
21294
|
Untitled by @xaviermoore | Stardance
|
xaviermoore
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled by @xaviermoore | Stardance
|
1792677131.6650126
|
1793281931.6650126
|
|
21296
|
My very own WebOS by @xaviermoore | Stardance
|
xaviermoore
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @xaviermoore | Stardan Title: My very own WebOS by @xaviermoore | Stardance...
|
1792630211.7286549
|
1793235011.7286549
|
|
26709
|
Frictionless by @xavierb | Stardance
|
xavierb
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @xavierb | Stardance
|
1793181181.8842828
|
1793785981.8842828
|
|
36144
|
Focus Pet by @xavier_teixeira | Stardance
|
xavier_teixeira
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Focus Pet by @xavier_teixeira | Stardance
|
1792659019.3617964
|
1793263819.3617964
|
|
39430
|
Frictionless by @xavier_teixeira | Stardance
|
xavier_teixeira
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @xavier_teixeira | Stardanc Title: Frictionless by @xavier_teixeira | Stardance...
|
1792655691.1840937
|
1793260491.1840937
|
|
39431
|
My very own WebOS by @xavier_teixeira | Stardance
|
xavier_teixeira
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @xavier_teixeira | Sta Title: My very own WebOS by @xavier_teixeira | Stardance...
|
1793134310.9345021
|
1793739110.9345021
|