|
20451
|
My awesome macropad! by @python | Stardance
|
python
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @python | Stardance
|
1793512624.9919946
|
1794117424.9919946
|
|
20452
|
My very own WebOS by @anshika_minocha | Stardance
|
anshika_minocha
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @anshika_minocha | Sta Title: My very own WebOS by @anshika_minocha | Stardance...
|
1793976758.9737382
|
1794581558.9737382
|
|
20453
|
My very own WebOS by @akshanna_arullendran | Stard My very own WebOS by @akshanna_arullendran | Stardance...
|
akshanna_arullendran
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @akshanna_arullendran Title: My very own WebOS by @akshanna_arullendran | Stardance...
|
1793573272.527402
|
1794178072.527402
|
|
20454
|
NULL
|
NULL
|
0
|
0.0
|
0
|
[]
|
[]
|
|
1793933498.0840542
|
1794797498.0840542
|
|
20455
|
My very own WebOS by @Roukia | Stardance
|
Roukia
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @Roukia | Stardance
|
1793839671.2648299
|
1794444471.2648299
|
|
20456
|
My awesome macropad! by @267gxl01 | Stardance
|
267gxl01
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @267gxl01 | Stardan Title: My awesome macropad! by @267gxl01 | Stardance...
|
1794081120.485512
|
1794685920.485512
|
|
20457
|
My very own WebOS by @notaskywalker779 | Stardance
|
notaskywalker779
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @notaskywalker779 | St Title: My very own WebOS by @notaskywalker779 | Stardance...
|
1794019894.3811831
|
1794624694.3811831
|
|
20458
|
PC Workshop by @Ronald08 | Stardance
|
Ronald08
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: PC Workshop by @Ronald08 | Stardance
|
1793854246.9636204
|
1794459046.9636204
|
|
20459
|
Dum-E by @Ishanth | Stardance
|
Ishanth
|
0
|
6.84
|
0
|
[]
|
[{"post_id": 53458, "ts": "202 [{"post_id": 53458, "ts": "2026-08-24T01:00:05Z", "hours": 0.4931, "text": "Most of the firmware has been updated including the schematics. I am still in the process of making the test and build files because there is some error going on with the test kinematics on my view window. Sadly smth went wrong with wakatime cuz I havent coded in a while so I just assumed it was turned on.. Unfortunately I only got like a fraction of my actual coding time đ"}, {"post_id": 41005, "ts": "2026-08-04T21:49:34Z", "hours": 2.9169, "text": "Just got the new CAD complete cuz the old one looked ugly.. I have most of the parts already 3D printed. Right now I am working on the code and some other things."}, {"post_id": 15462, "ts": "2026-06-25T04:19:28Z", "hours": 0.4669, "text": "Made some edits to the mecanum wheels.. They were positioned incorrectly and the wheel was also designed wrong"}, {"post_id": 14276, "ts": "2026-06-23T10:08:47Z", "hours": 1.6, "text": "Yess.. I have finally completed the whole design. This time everything was well thought out. Instead of normal wheels I have decided to use mecanum wheels for omnidirectional movement. Also there will be two cameras instead of one. The first camera is on the chassis as eyes. The eyes give depth perception so the robot can judge how far away an object is without a depth sensor. The second camera will be on the arm head for object detection. Electronics and the battery sit low at the back of the chassis as a counterweight to balance the arm mounted at the front, keeping the center of gravity stable even when the arm is fully extended. The arm has 6 degrees of freedom plus a gripper claw. Serial bus servos give position, voltage, and temperature feedback at every joint, which means the arm always knows exactly where it is, no guessing, no drifting. Inverse kinematics handles all the math of translating âgo to point (x, y, z) in spaceâ into the correct angles for all 6 joints simultaneously, so I can give the robot a target position in plain language and it figures out how to get there. Voice commands flow through a full natural language pipeline: a wake word detector listens constantly for âHey Dum-E,â then Whisper transcribes what I say, then an LLM interprets the intent and converts it into structured robot commands, things like pick up the red block, move left 10 centimeters, go to the charging station, lift your arm, or grab that. The full pipeline from voice command to physical grab is: wake word, then speech to text, then LLM intent parsing, then object detection, then coordinate mapping, then inverse kinematics, then servo motion. All of this runs on the Raspberry Pi 5 with an Arduino handling the real-time motor and servo PWM timing underneath, because the Piâs Linux scheduler isnât real-time and would cause jittery motion if it controlled servos directly."}, {"post_id": 11851, "ts": "2026-06-19T09:01:57Z", "hours": 1.3603, "text": "Devlog #1: Building Dum-E: A Voice-Controlled Mobile Robot Arm. Hey everyone! Iâm building a desktop robot arm inspired by Dum-E from Iron Man the clumsy little arm that Tony Stark keeps yelling at. Except mine is tiny. The concept is a 4-wheeled mecanum (omni) rover base with a full 5-joint robotic arm mounted on the back, two cameras on the arm head for eyes, and voice control so I can literally talk to it and it responds with movement and personality: beeps, whirs, droopy sad poses when I scold it, excited wiggling when I praise it. Still in design phase but parts list is locked and Iâm about to submit for funding. More updates soon as I start actually building!"}]...
|
Title: Dum-E by @Ishanth | Stardance
Devlogs:
Dev Title: Dum-E by @Ishanth | Stardance
Devlogs:
Devlog #1: Building Dum-E: A Voice-Controlled Mobile Robot Arm. Hey everyone! Iâm building a desktop robot arm inspired by Dum-E from Iron Man the clumsy little arm that Tony Stark keeps yelling at. Except mine is tiny. The concept is a 4-wheeled mecanum (omni) rover base with a full 5-joint robotic arm mounted on the back, two cameras on the arm head for eyes, and voice control so I can literally talk to it and it responds with movement and personality: beeps, whirs, droopy sad poses when I scold it, excited wiggling when I praise it. Still in design phase but parts list is locked and Iâm about to submit for funding. More updates soon as I start actually building!
Yess.. I have finally completed the whole design. This time everything was well thought out. Instead of normal wheels I have decided to use mecanum wheels for omnidirectional movement. Also there will be two cameras instead of one. The first camera is on the chassis as eyes. The eyes give depth perception so the robot can judge how far away an object is without a depth sensor. The second camera will be on the arm head for object detection. Electronics and the battery sit low at the back of the chassis as a counterweight to balance the arm mounted at the front, keeping the center of gravity stable even when the arm is fully extended. The arm has 6 degrees of freedom plus a gripper claw. Serial bus servos give position, voltage, and temperature feedback at every joint, which means the arm always knows exactly where it is, no guessing, no drifting. Inverse kinematics handles all the math of translating âgo to point (x, y, z) in spaceâ into the correct angles for all 6 joints simultaneously, so I can give the robot a target position in plain language and it figures out how to get there. Voice commands flow through a full natural language pipeline: a wake word detector listens constantly for âHey Dum-E,â then Whisper transcribes what I say, then an LLM interprets the intent and converts it into structured robot commands, things like pick up the red block, move left 10 centimeters, go to the charging station, lift your arm, or grab that. The full pipeline from voice command to physical grab is: wake word, then speech to text, then LLM intent parsing, then object detection, then coordinate mapping, then inverse kinematics, then servo motion. All of this runs on the Raspberry Pi 5 with an Arduino handling the real-time motor and servo PWM timing underneath, because the Piâs Linux scheduler isnât real-time and would cause jittery motion if it controlled servos directly.
Made some edits to the mecanum wheels.. They were positioned incorrectly and the wheel was also designed wrong
Just got the new CAD complete cuz the old one looked ugly.. I have most of the parts already 3D printed. Right now I am working on the code and some other things.
Most of the firmware has been updated including the schematics. I am still in the process of making the test and build files because there is some error going on with the test kinematics on my view window. Sadly smth went wrong with wakatime cuz I havent coded in a while so I just assumed it was turned on.. Unfortunately I only got like a fraction of my actual coding time đ...
|
1793415378.2384527
|
1794020178.2384527
|
|
20460
|
My first slack bot! by @Juless | Stardance
|
Juless
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @Juless | Stardance
|
1793854308.1633186
|
1794459108.1633186
|
|
20461
|
My awesome macropad! by @sri_dudi | Stardance
|
sri_dudi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @sri_dudi | Stardan Title: My awesome macropad! by @sri_dudi | Stardance...
|
1793433296.622411
|
1794038096.622411
|
|
20462
|
FocusMate by @Ishanth | Stardance
|
Ishanth
|
1
|
4.7
|
36
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-19T20:54:31Z", "hours": 3.0, "multiplier": 10.69, "payout": 36, "blessing": "neutral", "text": "I created FocusMate, an AI-powered study assistant that uses computer vision and NLP to monitor focus, generate personalized quizzes, and improve study sessions. The most challenging part was integrating multiple AI technologies and designing accurate focus-tracking features while keeping the platform user-friendly. I am proud of building a system that combines real-time engagement analysis with personalized learning tools, and users can test it by exploring the quiz generation, study tracking, and productivity features on the platform.", "repo": "https://github.com/Ishanthr1/FocusMate", "demo": "https://focus-mate-gamma.vercel.app/"}]...
|
[{"post_id": 13043, "ts": "202 [{"post_id": 13043, "ts": "2026-06-21T10:19:50Z", "hours": 1.6956, "text": "Just made some edits.. the UI is fully upgraded and the music bar is easier to use. The site now also fully functions in most browsers (It was only chrome originally)."}, {"post_id": 12144, "ts": "2026-06-19T20:52:48Z", "hours": 3.3603, "text": "FocusMate FocusMate, an AI-powered study assistant designed to improve learning efficiency through computer vision and natural language processing. Built features that analyze webcam input to track user focus, posture, and study engagement in real time. Implemented AI-driven study tools that generate personalized quizzes and summaries based on learning materials. Designed functionality to support both individual and group study sessions with progress tracking and performance insights. Integrated multiple technologies, including machine learning, computer vision, and web development frameworks, to create a comprehensive educational platform."}]...
|
Title: FocusMate by @Ishanth | Stardance
Devlogs: Title: FocusMate by @Ishanth | Stardance
Devlogs:
FocusMate FocusMate, an AI-powered study assistant designed to improve learning efficiency through computer vision and natural language processing. Built features that analyze webcam input to track user focus, posture, and study engagement in real time. Implemented AI-driven study tools that generate personalized quizzes and summaries based on learning materials. Designed functionality to support both individual and group study sessions with progress tracking and performance insights. Integrated multiple technologies, including machine learning, computer vision, and web development frameworks, to create a comprehensive educational platform.
Just made some edits.. the UI is fully upgraded and the music bar is easier to use. The site now also fully functions in most browsers (It was only chrome originally).
Ships:
I created FocusMate, an AI-powered study assistant that uses computer vision and NLP to monitor focus, generate personalized quizzes, and improve study sessions. The most challenging part was integrating multiple AI technologies and designing accurate focus-tracking features while keeping the platform user-friendly. I am proud of building a system that combines real-time engagement analysis with personalized learning tools, and users can test it by exploring the quiz generation, study tracking, and productivity features on the platform....
|
1793940831.5600681
|
1794027231.5600681
|
|
20463
|
My very own WebOS by @kokomina946 | Stardance
|
kokomina946
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @kokomina946 | Stardan Title: My very own WebOS by @kokomina946 | Stardance...
|
1793836110.9966464
|
1794440910.9966464
|
|
20464
|
Game by @Viridis | Stardance
|
Viridis
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Game by @Viridis | Stardance
|
1793468856.562887
|
1794073656.562887
|
|
20465
|
My awesome macropad! by @shashanth | Stardance
|
shashanth
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @shashanth | Starda Title: My awesome macropad! by @shashanth | Stardance...
|
1793519811.1657076
|
1794124611.1657076
|
|
20466
|
My first slack bot! by @sri_dudi | Stardance
|
sri_dudi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @sri_dudi | Stardanc Title: My first slack bot! by @sri_dudi | Stardance...
|
1793454644.0618365
|
1794059444.0618365
|
|
20467
|
ROVER "Target Fidelity" by @SebDev | Stard ROVER "Target Fidelity" by @SebDev | Stardance...
|
SebDev
|
0
|
8.9
|
0
|
[]
|
[{"post_id": 18776, "ts": "202 [{"post_id": 18776, "ts": "2026-06-29T23:51:45Z", "hours": 4.3006, "text": "Devlog #2 â ROVER âTarget Fidelityâ Hey again! Been a while, and a LOT happened since devlog #1. Last time I had the math roughly done and was about to start modeling. Now the whole mobility system is basically designed in Fusion, joints and all. Let me catch you up. Round tubes and printed joints First big change: I switched the arms from square tube to round aluminum tube (Ă25 for the rocker, Ă20 for the bogie). Easier to find and easier to bond into joints. And instead of bending tubes or bolting plates, all the intersections are now 3D-printed PETG joints â the tubes slide straight in and get pinned with M4 bolts. The cool part is the joints set the angles (160° at the rocker apex, 150° at the bogie V), so every tube is just cut straight at 90°. Way simpler to build. The differential rabbit hole Okay this is where I spent most of my time. I had a âdifferentialâ that was just a rigid bar, and after reading the JPL docs more carefully I realized thatâs not actually a differential â it doesnât keep the chassis level, each side just does its own thing. The real JPL rover uses a rocking balancĂn with two link rods (bieletas) that connect the two rockers so when one climbs, the other drops and the body stays level. So I rebuilt it properly: a balancĂn that pivots in the center, two bieletas going down to clamps on each rocker. Took me a bunch of tries to get right. Things I learned the hard way: The bieletas need ball joints on both ends , not rigid connections, or the whole thing locks up (the balancĂn and rocker rotate in different planes). For the leveling to be symmetric, the balancĂn arm and the clamp offset have to be the same distance â I went with 180 mm on both, giving a clean 1:1 ratio. I put the balancĂn right over the rocker joint and the bieletas kept hitting the chassis edge. Fixed it by mounting the whole differential on top of the lid , outside the sealed box, like JPL does. Steering and leveling The wheels donât mount straight to the tubes anymore. The wheels sit in C-mounts with MG996R servos . All three mounts on a side share the same 90 mm vertical drop so the wheels end up level on flat ground. Had to angle the sockets (75° on the bogie, 80° on the rocker) to cancel out the tube tilt so the wheels hang vertical. Picked the motors (and a reality check) Bumped my mass estimate up to 30 kg to be safe, and that changed everything for the motors. Ran the torque numbers and a standard JGB37 wasnât gonna cut it for climbing. Found the JGB37 50RPM at I+D that does 40 kg¡cm â thatâs the one. Pairing 6 of them with 2Ă BTS7960 drivers (one per side), a PCA9685 for the steering servos, and a 12V LiPo to handle the ~26A peaks when climbing. Still need to confirm the encoder version for navigation. Whatâs next Finish the differential clamp + bieleta details and double-check the 1:1 in Motion Study Start the print-and-test phase Source the motors and get them spinning Thatâs it for 2! Slowly turning a dream into an actual machine. Thanks for reading!"}, {"post_id": 15491, "ts": "2026-06-25T05:50:23Z", "hours": 4.6006, "text": "Devlog #1 â ROVER âTarget Fidelityâ Hello! First devlog for my Stardance project, so let me quickly show what Iâm building. ROVER âTarget Fidelityâ is a low-cost autonomous rover that drives itself over rough terrain like dirt, gravel and grass. It grabs soil and plant samples on its own and even runs biology and geology tests onboard. Think tiny Mars rover, but built with a 3D printer, cheap motors and a Raspberry Pi instead of a NASA budget. It uses a rocker-bogie suspension (same thing Perseverance has) so it keeps all six wheels on the ground no matter how rough it gets. Thatâs the goal, starting with the movement and the arm. This first log is all about the ideation process. Research first I didnât wanna just wing the suspension so I dug into how rocker-bogie actually works. Two papers shaped the design: Verma et al. (2017) for the formulas to size the arms and wheels, and Singh & Jain (2020) for how the load spreads out and how it climbs stuff. I also read NASA JPLâs Open Source Rover docs for the differential and joints. Main takeaways: Six wheels in a 3-3 layout keeps at least four touching the ground all the time. Itâs fully passive, no springs no shocks, the geometry does all the work. The bogie pivot position matters a lot for grip. I went with Case 2 (centered pivot) cause it splits weight evenly between front and middle wheel, so less spin on loose dirt. The calculations Worked out the sizes for what I wanted: chassis 600 mm wide by 1200 mm long, ~150 mm/s, able to climb 1.5x the wheel size. Started with the wheel. Went 200 mm diameter (cause why not), ran the speed formula and got ~14.3 rpm at the wheel for my target speed. Fine for most gearmotors, and if I need more rpm Iâll add gears or change the diameter. Then the wheelbase. Subtract front and rear wheel radius from the chassis length, gave me 1000 mm between axles. Placed the three wheels per side (front at 0, middle at 430 mm, rear at 1000 mm) and stuck the bogie pivot right between the front and middle wheel. For the arms I used the angle formulas but with chiller terrain angles instead of the mount-everest climbing one the paper uses. Got a rocker arm ~800 mm total (two 400 mm pieces) at 10° and bogie arms of 223 mm each at 15°. The bogie ends up a V with its two sockets meeting at 150°. Leaves ~158 mm of clearance under the chassis. Also ran the loads. Rear wheel takes the most (40%), so thatâs the part I gotta stress test hardest later. My 300 mm obstacle target is only 75% of the mechanismâs max, so comfy margin there, or at least I hope so. Whatâs next Now that the math is kinda ready, Iâm into the make and re-make phase to see how accurate the model is. Plan is to model everything for 3D printing and build a first test version using plastic tubes instead of aluminum for the arms, so I can test the geometry and run the motors without dropping a ton of money. Rather find out somethingâs wrong on a cheap plastic prototype than after cutting expensive aluminum. Next goals: Finish the printable joints Build a cheap plastic test frame Get the drive motors spinning Thatâs it for devlog #1! Next time I should have actual parts to show. Thanks for reading! (sorry if my English is off, not my first language.)"}]...
|
Title: ROVER "Target Fidelity" by @SebDev Title: ROVER "Target Fidelity" by @SebDev | Stardance
Devlogs:
Devlog #1 â ROVER âTarget Fidelityâ Hello! First devlog for my Stardance project, so let me quickly show what Iâm building. ROVER âTarget Fidelityâ is a low-cost autonomous rover that drives itself over rough terrain like dirt, gravel and grass. It grabs soil and plant samples on its own and even runs biology and geology tests onboard. Think tiny Mars rover, but built with a 3D printer, cheap motors and a Raspberry Pi instead of a NASA budget. It uses a rocker-bogie suspension (same thing Perseverance has) so it keeps all six wheels on the ground no matter how rough it gets. Thatâs the goal, starting with the movement and the arm. This first log is all about the ideation process. Research first I didnât wanna just wing the suspension so I dug into how rocker-bogie actually works. Two papers shaped the design: Verma et al. (2017) for the formulas to size the arms and wheels, and Singh & Jain (2020) for how the load spreads out and how it climbs stuff. I also read NASA JPLâs Open Source Rover docs for the differential and joints. Main takeaways: Six wheels in a 3-3 layout keeps at least four touching the ground all the time. Itâs fully passive, no springs no shocks, the geometry does all the work. The bogie pivot position matters a lot for grip. I went with Case 2 (centered pivot) cause it splits weight evenly between front and middle wheel, so less spin on loose dirt. The calculations Worked out the sizes for what I wanted: chassis 600 mm wide by 1200 mm long, ~150 mm/s, able to climb 1.5x the wheel size. Started with the wheel. Went 200 mm diameter (cause why not), ran the speed formula and got ~14.3 rpm at the wheel for my target speed. Fine for most gearmotors, and if I need more rpm Iâll add gears or change the diameter. Then the wheelbase. Subtract front and rear wheel radius from the chassis length, gave me 1000 mm between axles. Placed the three wheels per side (front at 0, middle at 430 mm, rear at 1000 mm) and stuck the bogie pivot right between the front and middle wheel. For the arms I used the angle formulas but with chiller terrain angles instead of the mount-everest climbing one the paper uses. Got a rocker arm ~800 mm total (two 400 mm pieces) at 10° and bogie arms of 223 mm each at 15°. The bogie ends up a V with its two sockets meeting at 150°. Leaves ~158 mm of clearance under the chassis. Also ran the loads. Rear wheel takes the most (40%), so thatâs the part I gotta stress test hardest later. My 300 mm obstacle target is only 75% of the mechanismâs max, so comfy margin there, or at least I hope so. Whatâs next Now that the math is kinda ready, Iâm into the make and re-make phase to see how accurate the model is. Plan is to model everything for 3D printing and build a first test version using plastic tubes instead of aluminum for the arms, so I can test the geometry and run the motors without dropping a ton of money. Rather find out somethingâs wrong on a cheap plastic prototype than after cutting expensive aluminum. Next goals: Finish the printable joints Build a cheap plastic test frame Get the drive motors spinning Thatâs it for devlog #1! Next time I should have actual parts to show. Thanks for reading! (sorry if my English is off, not my first language.)
Devlog #2 â ROVER âTarget Fidelityâ Hey again! Been a while, and a LOT happened since devlog #1. Last time I had the math roughly done and was about to start modeling. Now the whole mobility system is basically designed in Fusion, joints and all. Let me catch you up. Round tubes and printed joints First big change: I switched the arms from square tube to round aluminum tube (Ă25 for the rocker, Ă20 for the bogie). Easier to find and easier to bond into joints. And instead of bending tubes or bolting plates, all the intersections are now 3D-printed PETG joints â the tubes slide straight in and get pinned with M4 bolts. The cool part is the joints set the angles (160° at the rocker apex, 150° at the bogie V), so every tube is just cut straight at 90°. Way simpler to build. The differential rabbit hole Okay this is where I spent most of my time. I had a âdifferentialâ that was just a rigid bar, and after reading the JPL docs more carefully I realized thatâs not actually a differential â it doesnât keep the chassis level, each side just does its own thing. The real JPL rover uses a rocking balancĂn with two link rods (bieletas) that connect the two rockers so when one climbs, the other drops and the body stays level. So I rebuilt it properly: a balancĂn that pivots in the center, two bieletas going down to clamps on each rocker. Took me a bunch of tries to get right. Things I learned the hard way: The bieletas need ball joints on both ends , not rigid connections, or the whole thing locks up (the balancĂn and rocker rotate in different planes). For the leveling to be symmetric, the balancĂn arm and the clamp offset have to be the same distance â I went with 180 mm on both, giving a clean 1:1 ratio. I put the balancĂn right over the rocker joint and the bieletas kept hitting the chassis edge. Fixed it by mounting the whole differential on top of the lid , outside the sealed box, like JPL does. Steering and leveling The wheels donât mount straight to the tubes anymore. The wheels sit in C-mounts with MG996R servos . All three mounts on a side share the same 90 mm vertical drop so the wheels end up level on flat ground. Had to angle the sockets (75° on the bogie, 80° on the rocker) to cancel out the tube tilt so the wheels hang vertical. Picked the motors (and a reality check) Bumped my mass estimate up to 30 kg to be safe, and that changed everything for the motors. Ran the torque numbers and a standard JGB37 wasnât gonna cut it for climbing. Found the JGB37 50RPM at I+D that does 40 kg¡cm â thatâs the one. Pairing 6 of them with 2Ă BTS7960 drivers (one per side), a PCA9685 for the steering servos, and a 12V LiPo to handle the ~26A peaks when climbing. Still need to confirm the encoder version for navigation. Whatâs next Finish the differential clamp + bieleta details and double-check the 1:1 in Motion Study Start the print-and-test phase Source the motors and get them spinning Thatâs it for 2! Slowly turning a dream into an actual machine. Thanks for reading!...
|
1793540972.1554284
|
1794145772.1554284
|
|
20468
|
My first slack bot! by @Gordey | Stardance
|
Gordey
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @Gordey | Stardance
|
1794030648.4861639
|
1794635448.4861639
|
|
20469
|
Untitled by @guhan_venkat | Stardance
|
guhan_venkat
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled by @guhan_venkat | Stardance
|
1793454543.2329218
|
1794059343.2329218
|
|
20470
|
Orange Atlas by @0range_ | Stardance
|
0range_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Orange Atlas by @0range_ | Stardance
|
1794016363.731536
|
1794621163.731536
|
|
20471
|
Frictionless by @_stardance | Stardance
|
_stardance
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @_stardance | Stardance
|
1793519707.2102427
|
1794124507.2102427
|
|
20472
|
Personal website by @Kylet4d6ht | Stardance
|
Kylet4d6ht
|
0
|
0.6
|
0
|
[]
|
[{"post_id": 10353, "ts": "202 [{"post_id": 10353, "ts": "2026-06-17T01:09:04Z", "hours": 0.5967, "text": "I am starting the website and made the framework"}]...
|
Title: Personal website by @Kylet4d6ht | Stardance Title: Personal website by @Kylet4d6ht | Stardance
Devlogs:
I am starting the website and made the framework...
|
1793840177.6987705
|
1794444977.6987705
|
|
20473
|
A Macro Pad by @Mason_Chen | Stardance
|
Mason_Chen
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: A Macro Pad by @Mason_Chen | Stardance
|
1793512513.8605125
|
1794117313.8605125
|
|
20474
|
My first slack bot! by @JohnR | Stardance
|
JohnR
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @JohnR | Stardance
|
1793454789.9044564
|
1794059589.9044564
|
|
20475
|
Untitled by @267gxl01 | Stardance
|
267gxl01
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled by @267gxl01 | Stardance
|
1793411671.3266473
|
1794016471.3266473
|
|
20476
|
Untitled project by @Ay7in_Hu44ain | Stardance
|
Ay7in_Hu44ain
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled project by @Ay7in_Hu44ain | Starda Title: Untitled project by @Ay7in_Hu44ain | Stardance...
|
1793404163.7050745
|
1794008963.7050745
|
|
20477
|
Web site by @Ahror | Stardance
|
Ahror
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Web site by @Ahror | Stardance
|
1793436676.560629
|
1794041476.560629
|
|
20478
|
ARPANET Simulation by @armadillomike | Stardance
|
armadillomike
|
0
|
1.09
|
0
|
[]
|
[{"post_id": 10363, "ts": "202 [{"post_id": 10363, "ts": "2026-06-17T01:25:19Z", "hours": 1.0931, "text": "I set up the 1969 version of ARPANET I set it up using GNS3 with Alpine Linux as the computers and VyOS as the routers. It took a bit of setting up as I had to manually set all the IPs and connections. At the end I was able to ping all the connected devices from a single device. The screenshot shows all the routers and computers and their connections."}]...
|
Title: ARPANET Simulation by @armadillomike | Star Title: ARPANET Simulation by @armadillomike | Stardance
Devlogs:
I set up the 1969 version of ARPANET I set it up using GNS3 with Alpine Linux as the computers and VyOS as the routers. It took a bit of setting up as I had to manually set all the IPs and connections. At the end I was able to ping all the connected devices from a single device. The screenshot shows all the routers and computers and their connections....
|
1793480115.4120462
|
1794084915.4120462
|
|
20479
|
My very own WebOS by @aneeshparasa | Stardance
|
aneeshparasa
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @aneeshparasa | Starda Title: My very own WebOS by @aneeshparasa | Stardance...
|
1794027064.367281
|
1794631864.367281
|
|
20480
|
My very own WebOS by @orellanajosue2911 | Stardanc My very own WebOS by @orellanajosue2911 | Stardance...
|
orellanajosue2911
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @orellanajosue2911 | S Title: My very own WebOS by @orellanajosue2911 | Stardance...
|
1793804080.5244627
|
1794408880.5244627
|
|
20481
|
A Very Generic Photo Album Maker by @ishaan_halger A Very Generic Photo Album Maker by @ishaan_halgeri | Stardance...
|
ishaan_halgeri
|
0
|
1.16
|
0
|
[]
|
[{"post_id": 10854, "ts": "202 [{"post_id": 10854, "ts": "2026-06-17T19:59:28Z", "hours": 1.1606, "text": "Devlog #1, I started the album maker today and basically, I just wrote up the features that I wanted; an album viewer and sorter on the home page, an image carousel, a âretouchâ feature, and a âsmart sortâ button that analyzes the image and automatically assigns it to the designated album"}]...
|
Title: A Very Generic Photo Album Maker by @ishaan Title: A Very Generic Photo Album Maker by @ishaan_halgeri | Stardance
Devlogs:
Devlog #1, I started the album maker today and basically, I just wrote up the features that I wanted; an album viewer and sorter on the home page, an image carousel, a âretouchâ feature, and a âsmart sortâ button that analyzes the image and automatically assigns it to the designated album...
|
1793559311.7334015
|
1794164111.7334015
|
|
20482
|
My first slack bot! by @skspatel8112 | Stardance
|
skspatel8112
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @skspatel8112 | Star Title: My first slack bot! by @skspatel8112 | Stardance...
|
1793814797.4454796
|
1794419597.4454796
|
|
20483
|
Pulse by @mithbhasker | Stardance
|
mithbhasker
|
2
|
71.0
|
378
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-19T02:27:09Z", "hours": 16.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a website to help people like my dad who is a manager manage his team without multiple tools.", "repo": "https://github.com/Mithilessh2010/Pulse", "demo": "https://pulse-beta-nine.vercel.app/"}, {"ship_num": 2, "ts": "2026-08-01T05:26:05Z", "hours": 55.0, "multiplier": 9.75, "payout": 378, "blessing": "neutral", "text": "I did it for part of my startup this is the basic stuff I used a very basic AI looking UI but that is because I wanted base product out first but most core concepts I did.", "repo": "https://github.com/Mithilessh2010/Pulse", "demo": "https://pulse-beta-nine.vercel.app/"}]...
|
[{"post_id": 73434, "ts": "202 [{"post_id": 73434, "ts": "2026-09-25T02:36:18Z", "hours": 15.8133, "text": "I added some animations and to the bottom right corner of the website there is an AI chatbot and since I gave it a proper API key it can do much more making a managers life much easier"}, {"post_id": 36029, "ts": "2026-07-27T21:00:55Z", "hours": 17.9003, "text": "I couldnât get all the API keys for the integrations so for now I am going to ship this and add things for a later ship"}, {"post_id": 28738, "ts": "2026-07-15T05:36:35Z", "hours": 10.7378, "text": "I added the rest of the buttons and made sure a quick prototype is in work it looks good to me as of now more updates will happen"}, {"post_id": 26057, "ts": "2026-07-10T17:22:29Z", "hours": 17.2972, "text": "I finished cleaning up the UI for the dashboard itself as most buttons and containers were unsatisfactory, I am going to work on getting the API keys next"}, {"post_id": 10952, "ts": "2026-06-17T23:25:23Z", "hours": 1.8375, "text": "Reworked the app shell and related screens to match the latest Pulse UI pass, added the calls surface, refreshed shared styling and auth presentation, and updated mock data, state, and assets to support the new layout. Included the current deliverables and dependency updates tied to the build changes."}, {"post_id": 10717, "ts": "2026-06-17T16:07:40Z", "hours": 1.2131, "text": "The Pulse demo data was moved to a centralized persisted store so changes are saved across navigation, page refreshes, and browser restarts. A reset option was also added in Settings to restore the original sample workspace."}, {"post_id": 10403, "ts": "2026-06-17T03:05:03Z", "hours": 1.0364, "text": "The Ask Pulse AI assistant was improved with better context, smarter fallback responses, and a request timeout to make it more reliable. The system prompt and API were updated for better flexibility, UI components were enhanced with improved interactivity, data fields were made consistent, and the deliverable was updated with the latest changes."}, {"post_id": 10364, "ts": "2026-06-17T01:27:19Z", "hours": 4.725, "text": "I just finished the Home Page, it has cool animations and fonts to really grab the personâs attention and get them more interested in using PULSE and paying to use it. As you scroll many animations will happen and I am now coding the buttons to look at more info."}]...
|
Title: Pulse by @mithbhasker | Stardance
Devlogs: Title: Pulse by @mithbhasker | Stardance
Devlogs:
I just finished the Home Page, it has cool animations and fonts to really grab the personâs attention and get them more interested in using PULSE and paying to use it. As you scroll many animations will happen and I am now coding the buttons to look at more info.
The Ask Pulse AI assistant was improved with better context, smarter fallback responses, and a request timeout to make it more reliable. The system prompt and API were updated for better flexibility, UI components were enhanced with improved interactivity, data fields were made consistent, and the deliverable was updated with the latest changes.
The Pulse demo data was moved to a centralized persisted store so changes are saved across navigation, page refreshes, and browser restarts. A reset option was also added in Settings to restore the original sample workspace.
Reworked the app shell and related screens to match the latest Pulse UI pass, added the calls surface, refreshed shared styling and auth presentation, and updated mock data, state, and assets to support the new layout. Included the current deliverables and dependency updates tied to the build changes.
I finished cleaning up the UI for the dashboard itself as most buttons and containers were unsatisfactory, I am going to work on getting the API keys next
I added the rest of the buttons and made sure a quick prototype is in work it looks good to me as of now more updates will happen
I couldnât get all the API keys for the integrations so for now I am going to ship this and add things for a later ship
I added some animations and to the bottom right corner of the website there is an AI chatbot and since I gave it a proper API key it can do much more making a managers life much easier
Ships:
I did it for part of my startup this is the basic stuff I used a very basic AI looking UI but that is because I wanted base product out first but most core concepts I did.
I made a website to help people like my dad who is a manager manage his team without multiple tools....
|
1793980074.581913
|
1794066474.581913
|
|
20484
|
Frictionless by @Aryavdas | Stardance
|
Aryavdas
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @Aryavdas | Stardance
|
1793426087.2429113
|
1794030887.2429113
|
|
20485
|
Frictionless by @Meer | Stardance
|
Meer
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @Meer | Stardance
|
1793393390.618421
|
1793998190.618421
|
|
20486
|
Frictionless by @Maahi | Stardance
|
Maahi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @Maahi | Stardance
|
1793839932.3070874
|
1794444732.3070874
|
|
20487
|
Frictionless by @Seyon | Stardance
|
Seyon
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @Seyon | Stardance
|
1794084773.6155083
|
1794689573.6155083
|
|
20488
|
My awesome macropad! by @sheep_boy17 | Stardance
|
sheep_boy17
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My awesome macropad! by @sheep_boy17 | Star Title: My awesome macropad! by @sheep_boy17 | Stardance...
|
1794062931.6615493
|
1794667731.6615493
|
|
20489
|
IF-RC by @kojii | Stardance
|
kojii
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: IF-RC by @kojii | Stardance
|
1794041461.6886194
|
1794905461.6886194
|
|
20490
|
Phoenix - Web Game Framework by @openchanter | Sta Phoenix - Web Game Framework by @openchanter | Stardance...
|
openchanter
|
1
|
29.37
|
325
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-13T06:20:18Z", "hours": 25.0, "multiplier": 12.89, "payout": 325, "blessing": "neutral", "text": "I made Phoenix, a web-based game framework using TypeScript! It is designed to be easy to use and quick to make projects with. I used THREE.js for rendering and Planck.js for the physics engine. The features available in the engine vary from simple rendering components to rigidbodies, UI systems and particle systems! The engine also supports a proper scene hierarchy with objects being able to have children that inherit their translation and rotation. The most challenging part of this was just trying to iron out all of the small bugs that kept popping up in different areas of the engine while I was trying to add a new feature somewhere. Just a note about the demo though, it is meant to just show off the features of the engine, and the demo is not the product of this project but rather the actual engine and itâs API that can be used to make games! I also plan to make an actual game using this engine as my next project for Stardance!", "repo": "https://github.com/OpEnchanter/phoenix", "demo": "https://openchanter.github.io/phoenix"}]...
|
[{"post_id": 31045, "ts": "202 [{"post_id": 31045, "ts": "2026-07-19T03:58:27Z", "hours": 3.1128, "text": "Another devlog as I continue to work on my other project that uses this engine as a dependency. Since Iâve been actually using this engine for making something real, Iâve noticed that it has quite a few flaws that I didnât catch earlier on in the creation process. For example, when the window resized on the Y axis, the scale of the content within the window would also scale. This actually ended up causing a big issue with my new project as I had to convert screen-space mouse coordinates to positions in the world for placing objects in the editor. Fixing this was pretty simple and I just swapped out the old render resolution for a render scalar that gets multiplied by the window resolution to calculate the render resolution. Over the time of creating my new project there have also been some other small issues with things such as the button hitboxes and the engine not having the ability to resize objects in real time that I have since fixed. For the real time object resizing issue though, it was especially annoying because I had to resize the THREE.js Mesh object directly using the .scale.set() method on it which cannot be simply supplied with the size in pixels you want the object to be and is separate from the size of the geometry. To solve this I had to calculate how much I would have to multiply the scale of the geometry by to get the new scale. This ends up being the math equation, newScale / originalScale . Attached to this devlog are images, showing the window scaling fix in action as well as the scaling fix as it is used in my game. Now the scale of pixels stays exactly the same regardless of the scale of the window, and the 2nd block shown in the image with the Tiles picker is being scaled and rotated when the player hovers it. Overall, this project is becoming quite a bit larger than I originally intended as I work on it more while actually using it to make a real game. Thanks for reading this devlog!"}, {"post_id": 27962, "ts": "2026-07-13T22:18:53Z", "hours": 1.255, "text": "Another quick devlog as Iâve been adding features while trying to make an actual game with the engine! I realized that I hadnât added offsets for colliders, trigger colliders or collision callbacks, so I added all of those and that works now, and I also realized I needed a special renderer that could draw using THREE.jsâ InstancedMesh so I created the InstancedRenderer component that allows for that InstancedMesh to be used, this should afford a decent performance boost for any games that have the ground made up of tiles (if used correctly). The image attached is an image of the game Iâve started working on!"}, {"post_id": 27541, "ts": "2026-07-13T06:08:25Z", "hours": 1.1381, "text": "Another short devlog, again about UI! I got around to adding a proper button component to the engine that supports both a hover and click state! Currently I am using it in one of the demos for a button that slows down time to 1/10 speed when clicked. When I was trying to get this working, I realized I had a pretty major bug with how the scale of the window worked, which was causing issues with mouse inputs not lining up correctly with the engineâs visual output, but after fixing that it works great! The implementation for usage is also pretty simple with the Phoenix.Button() component just having two optional fields, one for onHoverCallback and one for onClickCallback. Here is an example of an onClickCallback being supplied to a button component: new Phoenix . Button (() => { app . args . timescale = ( app . args . timescale == 1 ) ? 0.1 : 1 }) Thanks for reading my boring UI yap again!!"}, {"post_id": 27482, "ts": "2026-07-13T02:51:20Z", "hours": 1.4086, "text": "Very small devlog this time! Iâve now added support for screen-space rendering of objects (rendering of objects relative to the screen rather than the world). This will be very important for adding proper UI components such as buttons, switches, sliders and text boxes to the engine later! With the addition of screen space rendering I also added a new component specifically for it, being the UIRenderer component. It behaves exactly like the standard Renderer component, but it renders to the THREE.js scene that the output of the main scene is rendered to for applying screen-space shaders. This also has the side effect of UI elements being able to ignore the current screen-space shader, so they donât get distorted or become unreadable in any other way. Hereâs a little code example for how the screen-space rendering works when creating an object: app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 64 , 96 ), 0 , new Phoenix . Vector2 ( 16 , 16 )), new Phoenix . Sprite ( \" assets/brick.png \" ), new Phoenix . UIRenderer ( 1 ) ) This little bit of code would create an object at coordinates (64, 96) but it would follow the camera rather than staying put in the world! In my next devlog I plan to actually add components for proper interactivity with UI components! Thanks for reading my yap!! Byeeee!"}, {"post_id": 26985, "ts": "2026-07-12T03:38:26Z", "hours": 1.4139, "text": "Hiya there! Another devlog on this project!! This time I added an actual particle system to the engine that can be used to spawn a bunch of little particles. Itâs still missing a bit of customization such as turning off gravity for particles or the ability to change particleâs initial velocity, but so far it isnât causing any lag and seems to work well! I had to figure out THREE.jsâ InstancedMesh system to get this working without making the game run horribly, but I got it and it works now! The docs are also updated to reflect this new feature. And the ParticleSystem is used like any other component by just adding it to an object like the following: app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , 0 ), 0 , new Phoenix . Vector2 ( 32 , 32 )), new Phoenix . ParticleSystem ( \" assets/brick.png \" , 10 , new Phoenix . Vector2 ( 24 , 24 )) ) ) The entire system for particles is self contained and doesnât rely on any other components like the Renderer and Sprite because I felt it would be better to separate it due to the fact that the particles using an InstancedMesh, and the user might want to have particles have a different texture than their emitter. As shown in the images, the ParticleSystem can support a lot of particles and from some testing it is able to handle 10, 1000 and 10000 particles with no lag, but 100000 particles is stretching it a bit. I mean who would put over 10000 particles on screen at a time though, right?"}, {"post_id": 26131, "ts": "2026-07-10T19:01:01Z", "hours": 3.8183, "text": "Yay! Another devlog and even more hours poured into this project! This time I finally got around to reworking how the engine works to actually allow for objects to have children! In the past all objects were stored in a flat array which didnât allow for any object parenting of any kind, but now the root of the scene is just another GameObject, so it can have children and those children can have children and so on forever. As you can see in the example photos, the brick object on the left has a smaller checkerboard-pattern object as a child of it that moves relative to itâs parentâs rotation and position. On the development side of things, adding objects to the scene as a whole remains exactly the same with the way the addition of objects simply being changed to having them be children of the scene root, but now all objects have a new method, GameObject.addChild(object: GameObject) . This allows any object have a child added to it, for example: player . addChild ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , 0 ), 0 , new Phoenix . Vector2 ( 16 , 16 )), new Phoenix . Sprite ( \" assets/null.png \" ), new Phoenix . Renderer ( 1 ) )); This would just add a new smaller object to the player object with the null.png sprite, and this is exactly what is happening in the screenshots attached to this."}, {"post_id": 25126, "ts": "2026-07-09T04:22:25Z", "hours": 2.8756, "text": "I decided to use the feature I added to the engine a while ago that allows for custom screen space shaders to create a lighting shader for the game based on some simple raymarching! Iâm going to work on getting it more polished and then implement it as a variable exposed by the main engine as something that can be used in any project. The usage of the shader isnât too complicated, it just requires data about the lights to be supplied to the shader via uniforms. let lightPositions = [ new THREE . Vector2 ( - 128 , 128 ), new THREE . Vector2 ( 64 , 128 ) ] let lightScales = [ new THREE . Vector2 ( 512 , 512 ), new THREE . Vector2 ( 512 , 512 ) ] let lightColors = [ new THREE . Vector3 ( 1 , 0.3 , 0 ), new THREE . Vector3 ( 0 , 1 , 0.3 ) ] This would be supplied to the Appâs options to override the shader. shaderOverride : { vertexShader : Phoenix . DefaultVertexShader , fragmentShader : LitShader , uniforms : { uLightPositions : { value : lightPositions }, uLightScales : { value : lightScales }, uLightColors : { value : lightColors } } } And then positions should be updated every frame to keep them in world space. app . addFrameIntervalCallback (() => { let lps = [] for ( const lightPos of lightPositions ) { const p = new THREE . Vector3 ( lightPos . x , lightPos . y , 0 ); p . project ( app . camera ); const x = ( p . x + 1 ) / 2 const y = ( p . y + 1 ) / 2 lps . push ( new THREE . Vector2 ( x , y )) } app . screenSpaceShader . uniforms . uLightPositions ! . value = lps let scls = [] for ( const lightScale of lightScales ) { const x = lightScale . x ! / rScale.x const y = lightScale . y ! / rScale.y scls . push ( new THREE . Vector2 ( x , y )) } app . screenSpaceShader . uniforms . uLightScales ! . value = scls }) Edit: I completely forgot about this but at some point I added support for animated sprites using the AnimatedSprite class which can be supplied an array of strings representing the paths to the image for each frame as well as a animation rate (number of game frames each animation frame is shown for)"}, {"post_id": 24576, "ts": "2026-07-08T08:10:21Z", "hours": 2.9547, "text": "I did a bunch of backend stuff, adding features and making the engine overall better. My most recent addition to this is the use of a unified renderer component, where rather than having separate components handling the rendering of text, canvas sprites and normal sprites individually and with duplicate code, the main renderer component automatically finds any sprite type and renders it! For example, in the scenes below: the text in past versions would have been rendered with a TextRenderer component, whereas now there is a TextSprite component that feeds a texture to a Renderer component on the object. New Version const text = new Phoenix . TextSprite ( \" Hello world! \" , { fontSize : 32 , backgroundColor : \" #7fefcf \" , padding : 8 }); app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , - 83 ), 0 , new Phoenix . Vector2 ( text . texture ! . width , text . texture ! . height )), text , new Phoenix . Renderer ( 1 ) )); Old Version app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , - 83 ), 0 , new Phoenix . Vector2 ( 0 , 0 )), new Phoenix . TextRenderer ( \" Hello world! \" , { fontSize : 32 , backgroundColor : \" #7fefcf \" , padding : 8 }, 1 )"}, {"post_id": 15461, "ts": "2026-06-25T04:17:31Z", "hours": 2.4086, "text": "Big update! I finally actually got around to making the demo scenes built with this engine publish on GitHub pages ( here ). I also added a circle collider component and a text renderer which in turn relies on a HTML Canvas Renderer so thereâs also now an easier way to create procedural assets for games."}, {"post_id": 14176, "ts": "2026-06-23T05:13:33Z", "hours": 1.6892, "text": "I finally added support for getting inputs within a component without using a web API to register an event listener and then having to deal with destroying that when the object get unloaded! I then updated the test scene to reflect that with a new component added to each object in a tower that adds an impulse when the W key is pressed. The scene can also be switched with the H key."}, {"post_id": 10659, "ts": "2026-06-17T14:54:58Z", "hours": 3.1258, "text": "I added screen-space shader support for now, the shader canât be overridden but Iâll change that as well as allowing for the shaders attached to individual objects to be overridden."}, {"post_id": 10375, "ts": "2026-06-17T01:44:28Z", "hours": 4.535, "text": "So far Iâve added all the basics, scenes, objects, physics implementation and rendering. The rendering is currently using a basic HTML canvas method, but I am planning to update it to THREE.js for faster rendering and support for complex shader effects. This will probably be a relatively short project and I probably wont make many devlogs for this. Itâs kind of hard to show off an engine with images, and without showing the code, so I donât know how much visual progress Iâll be able to show, but Iâll definately be able to show a lot more for the game Iâm planning on making that will use this engine!"}]...
|
Title: Phoenix - Web Game Framework by @openchante Title: Phoenix - Web Game Framework by @openchanter | Stardance
Devlogs:
So far Iâve added all the basics, scenes, objects, physics implementation and rendering. The rendering is currently using a basic HTML canvas method, but I am planning to update it to THREE.js for faster rendering and support for complex shader effects. This will probably be a relatively short project and I probably wont make many devlogs for this. Itâs kind of hard to show off an engine with images, and without showing the code, so I donât know how much visual progress Iâll be able to show, but Iâll definately be able to show a lot more for the game Iâm planning on making that will use this engine!
I added screen-space shader support for now, the shader canât be overridden but Iâll change that as well as allowing for the shaders attached to individual objects to be overridden.
I finally added support for getting inputs within a component without using a web API to register an event listener and then having to deal with destroying that when the object get unloaded! I then updated the test scene to reflect that with a new component added to each object in a tower that adds an impulse when the W key is pressed. The scene can also be switched with the H key.
Big update! I finally actually got around to making the demo scenes built with this engine publish on GitHub pages ( here ). I also added a circle collider component and a text renderer which in turn relies on a HTML Canvas Renderer so thereâs also now an easier way to create procedural assets for games.
I did a bunch of backend stuff, adding features and making the engine overall better. My most recent addition to this is the use of a unified renderer component, where rather than having separate components handling the rendering of text, canvas sprites and normal sprites individually and with duplicate code, the main renderer component automatically finds any sprite type and renders it! For example, in the scenes below: the text in past versions would have been rendered with a TextRenderer component, whereas now there is a TextSprite component that feeds a texture to a Renderer component on the object. New Version const text = new Phoenix . TextSprite ( " Hello world! " , { fontSize : 32 , backgroundColor : " #7fefcf " , padding : 8 }); app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , - 83 ), 0 , new Phoenix . Vector2 ( text . texture ! . width , text . texture ! . height )), text , new Phoenix . Renderer ( 1 ) )); Old Version app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , - 83 ), 0 , new Phoenix . Vector2 ( 0 , 0 )), new Phoenix . TextRenderer ( " Hello world! " , { fontSize : 32 , backgroundColor : " #7fefcf " , padding : 8 }, 1 )
I decided to use the feature I added to the engine a while ago that allows for custom screen space shaders to create a lighting shader for the game based on some simple raymarching! Iâm going to work on getting it more polished and then implement it as a variable exposed by the main engine as something that can be used in any project. The usage of the shader isnât too complicated, it just requires data about the lights to be supplied to the shader via uniforms. let lightPositions = [ new THREE . Vector2 ( - 128 , 128 ), new THREE . Vector2 ( 64 , 128 ) ] let lightScales = [ new THREE . Vector2 ( 512 , 512 ), new THREE . Vector2 ( 512 , 512 ) ] let lightColors = [ new THREE . Vector3 ( 1 , 0.3 , 0 ), new THREE . Vector3 ( 0 , 1 , 0.3 ) ] This would be supplied to the Appâs options to override the shader. shaderOverride : { vertexShader : Phoenix . DefaultVertexShader , fragmentShader : LitShader , uniforms : { uLightPositions : { value : lightPositions }, uLightScales : { value : lightScales }, uLightColors : { value : lightColors } } } And then positions should be updated every frame to keep them in world space. app . addFrameIntervalCallback (() => { let lps = [] for ( const lightPos of lightPositions ) { const p = new THREE . Vector3 ( lightPos . x , lightPos . y , 0 ); p . project ( app . camera ); const x = ( p . x + 1 ) / 2 const y = ( p . y + 1 ) / 2 lps . push ( new THREE . Vector2 ( x , y )) } app . screenSpaceShader . uniforms . uLightPositions ! . value = lps let scls = [] for ( const lightScale of lightScales ) { const x = lightScale . x ! / rScale.x const y = lightScale . y ! / rScale.y scls . push ( new THREE . Vector2 ( x , y )) } app . screenSpaceShader . uniforms . uLightScales ! . value = scls }) Edit: I completely forgot about this but at some point I added support for animated sprites using the AnimatedSprite class which can be supplied an array of strings representing the paths to the image for each frame as well as a animation rate (number of game frames each animation frame is shown for)
Yay! Another devlog and even more hours poured into this project! This time I finally got around to reworking how the engine works to actually allow for objects to have children! In the past all objects were stored in a flat array which didnât allow for any object parenting of any kind, but now the root of the scene is just another GameObject, so it can have children and those children can have children and so on forever. As you can see in the example photos, the brick object on the left has a smaller checkerboard-pattern object as a child of it that moves relative to itâs parentâs rotation and position. On the development side of things, adding objects to the scene as a whole remains exactly the same with the way the addition of objects simply being changed to having them be children of the scene root, but now all objects have a new method, GameObject.addChild(object: GameObject) . This allows any object have a child added to it, for example: player . addChild ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , 0 ), 0 , new Phoenix . Vector2 ( 16 , 16 )), new Phoenix . Sprite ( " assets/null.png " ), new Phoenix . Renderer ( 1 ) )); This would just add a new smaller object to the player object with the null.png sprite, and this is exactly what is happening in the screenshots attached to this.
Hiya there! Another devlog on this project!! This time I added an actual particle system to the engine that can be used to spawn a bunch of little particles. Itâs still missing a bit of customization such as turning off gravity for particles or the ability to change particleâs initial velocity, but so far it isnât causing any lag and seems to work well! I had to figure out THREE.jsâ InstancedMesh system to get this working without making the game run horribly, but I got it and it works now! The docs are also updated to reflect this new feature. And the ParticleSystem is used like any other component by just adding it to an object like the following: app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 0 , 0 ), 0 , new Phoenix . Vector2 ( 32 , 32 )), new Phoenix . ParticleSystem ( " assets/brick.png " , 10 , new Phoenix . Vector2 ( 24 , 24 )) ) ) The entire system for particles is self contained and doesnât rely on any other components like the Renderer and Sprite because I felt it would be better to separate it due to the fact that the particles using an InstancedMesh, and the user might want to have particles have a different texture than their emitter. As shown in the images, the ParticleSystem can support a lot of particles and from some testing it is able to handle 10, 1000 and 10000 particles with no lag, but 100000 particles is stretching it a bit. I mean who would put over 10000 particles on screen at a time though, right?
Very small devlog this time! Iâve now added support for screen-space rendering of objects (rendering of objects relative to the screen rather than the world). This will be very important for adding proper UI components such as buttons, switches, sliders and text boxes to the engine later! With the addition of screen space rendering I also added a new component specifically for it, being the UIRenderer component. It behaves exactly like the standard Renderer component, but it renders to the THREE.js scene that the output of the main scene is rendered to for applying screen-space shaders. This also has the side effect of UI elements being able to ignore the current screen-space shader, so they donât get distorted or become unreadable in any other way. Hereâs a little code example for how the screen-space rendering works when creating an object: app . addObject ( app . createObject ( new Phoenix . Transform ( new Phoenix . Vector2 ( 64 , 96 ), 0 , new Phoenix . Vector2 ( 16 , 16 )), new Phoenix . Sprite ( " assets/brick.png " ), new Phoenix . UIRenderer ( 1 ) ) This little bit of code would create an object at coordinates (64, 96) but it would follow the camera rather than staying put in the world! In my next devlog I plan to actually add components for proper interactivity with UI components! Thanks for reading my yap!! Byeeee!
Another short devlog, again about UI! I got around to adding a proper button component to the engine that supports both a hover and click state! Currently I am using it in one of the demos for a button that slows down time to 1/10 speed when clicked. When I was trying to get this working, I realized I had a pretty major bug with how the scale of the window worked, which was causing issues with mouse inputs not lining up correctly with the engineâs visual output, but after fixing that it works great! The implementation for usage is also pretty simple with the Phoenix.Button() component just having two optional fields, one for onHoverCallback and one for onClickCallback. Here is an example of an onClickCallback being supplied to a button component: new Phoenix . Button (() => { app . args . timescale = ( app . args . timescale == 1 ) ? 0.1 : 1 }) Thanks for reading my boring UI yap again!!
Another quick devlog as Iâve been adding features while trying to make an actual game with the engine! I realized that I hadnât added offsets for colliders, trigger colliders or collision callbacks, so I added all of those and that works now, and I also realized I needed a special renderer that could draw using THREE.jsâ InstancedMesh so I created the InstancedRenderer component that allows for that InstancedMesh to be used, this should afford a decent performance boost for any games that have the ground made up of tiles (if used correctly). The image attached is an image of the game Iâve started working on!
Another devlog as I continue to work on my other project that uses this engine as a dependency. Since Iâve been actually using this engine for making something real, Iâve noticed that it has quite a few flaws that I didnât catch earlier on in the creation process. For example, when the window resized on the Y axis, the scale of the content within the window would also scale. This actually ended up causing a big issue with my new project as I had to convert screen-space mouse coordinates to positions in the world for placing objects in the editor. Fixing this was pretty simple and I just swapped out the old render resolution for a render scalar that gets multiplied by the window resolution to calculate the render resolution. Over the time of creating my new project there have also been some other small issues with things such as the button hitboxes and the engine not having the ability to resize objects in real time that I have since fixed. For the real time object resizing issue though, it was especially annoying because I had to resize the THREE.js Mesh object directly using the .scale.set() method on it which cannot be simply supplied with the size in pixels you want the object to be and is separate from the size of the geometry. To solve this I had to calculate how much I would have to multiply the scale of the geometry by to get the new scale. This ends up being the math equation, newScale / originalScale . Attached to this devlog are images, showing the window scaling fix in action as well as the scaling fix as it is used in my game. Now the scale of pixels stays exactly the same regardless of the scale of the window, and the 2nd block shown in the image with the Tiles picker is being scaled and rotated when the player hovers it. Overall, this project is becoming quite a bit larger than I originally intended as I work on it more while actually using it to make a real game. Thanks for reading this devlog!
Ships:
I made Phoenix, a web-based game framework using TypeScript! It is designed to be easy to use and quick to make projects with. I used THREE.js for rendering and Planck.js for the physics engine. The features available in the engine vary from simple rendering components to rigidbodies, UI systems and particle systems! The engine also supports a proper scene hierarchy with objects being able to have children that inherit their translation and rotation. The most challenging part of this was just trying to iron out all of the small bugs that kept popping up in different areas of the engine while I was trying to add a new feature somewhere. Just a note about the demo though, it is meant to just show off the features of the engine, and the demo is not the product of this project but rather the actual engine and itâs API that can be used to make games! I also plan to make an actual game using this engine as my next project for Stardance!...
|
1793944485.8809958
|
1794030885.8809958
|
|
20491
|
My very own WebOS by @linomunozjesuselias | Starda My very own WebOS by @linomunozjesuselias | Stardance...
|
linomunozjesuselias
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My very own WebOS by @linomunozjesuselias | Title: My very own WebOS by @linomunozjesuselias | Stardance...
|
1793987290.0339577
|
1794592090.0339577
|
|
20492
|
My first slack bot! by @sheetal_ | Stardance
|
sheetal_
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: My first slack bot! by @sheetal_ | Stardanc Title: My first slack bot! by @sheetal_ | Stardance...
|
1794041318.5727072
|
1794646118.5727072
|
|
20493
|
PlayBrew - Homebrew for the Playdate! by @mindstor PlayBrew - Homebrew for the Playdate! by @mindstormpro3 | Stardance...
|
mindstormpro3
|
0
|
7.41
|
0
|
[]
|
[{"post_id": 39047, "ts": "202 [{"post_id": 39047, "ts": "2026-08-01T18:38:51Z", "hours": 5.8089, "text": "Devlog #1: PROGRESS! To sum it up: the firmware mod is almost done, and I am going to start on the homebrew menu! since the last devlog, I went through 4 iterations on the homebrew loader design: It. 1: The OG design , a patched update loop that runs my homebrew before the update loop begins, with a file open func to read payloads It. 2: same design , but using lower-level uC-fs file IO funcs since the regular ones didnt seem to work when elevated It. 3: New design , this time I patched the LoadPDX() function that loads games/apps to elevate permissions if a system app was being ran (there is an unpatched exploit to install any app as a system app so this route made sense) It. 4: New design a function is placed at the end of the firmware that just contains a single svc #2 , which is the assembly instruction that elevates your permissions and then returns, so that the caller gets elevated (this works because the CPU only will run elevation/permission change functions from firmware code, not loaded code like a game) Iteration #4 is the current iteration and I am actively working to get it⌠well⌠working. The current issue right now is for some reason it seems to crash when I run the homebrew app, but the firmware itself is fine so I am going to try a couple of things."}, {"post_id": 10405, "ts": "2026-06-17T03:06:43Z", "hours": 1.5997, "text": "Devlog #0 - A quick Recap This is my first devlog for PlayBrew, my Playdate Homebrew, and it is mostly focused on explaining what I have thus far. What is PlayBrew? Playbrew is a homebrew for the playdate game console that enables the user of the device (YOU!) to unlock your consoleâs true potential! You can code payloads, which are C scripts compiled into binary files, and then run them on-device with full low level firmware access (no sandboxing!!!). Possible payloads could be one that enables the bluetooth functionality, one that allows you to set a custom lock screen, and even one for game modding! (I have a whole list of cool ideas that I may share later) The state of things Sooo sadly right now PlayBrew is unfunctional đ⌠So far I have been able to modify the firmware to allow for ACE (arbitrary code execution (also donât worry the games canât access it so no worry of malware :D)) of some C code that gets compiled and appended to the firmware, but I am having issues with the filesystem and am unable to read the actual payloads. The way the arbitrary code runs is by modifying a function pointer to the main FW update loop to run my code, and then at the end of PlayBrewâs code it just returns into the FW update loop and the firmware runs as normal. sooo now whatâs next? Thereâs a couple things I have planned, kinda ranked in order of importance: Getting the FS to work (I am making progress on that rn) Making the payload build system (gonna need help with that lol⌠I hate the C compiler) expanding the API before the full v1 release (I have to manually expose all of the functions from the FW since their addresses can changeâŚ) Get sleep (so basically I havzzzzzzzzzzzzzzzzzzzz) make a way to dump the unlock code (itâs your FW decryption key) make an installer donât get DMCA takedownâed Sign me up! hold up there⌠even If you own a playdate, there are a few different things you need to know ahead of time, and in short, you canât install it. this is because: firmware for the device (specifically the pdfw file in a PlaydateOS.pdos (which is just a zip) file) is encrypted, so you gotta get your device specific key and write or find a tool to decrypt it, and I canât legally share one because of the really dumb law called the DMCA :( PlayBrew is ONLY compatable with rev. B devices (the newer ones) at this time. I donât have a rev. A to test it on but it is possible to port it, I just canât rn You need your unlock code, as required in the first point. The unlock code is a special decryption key used for decrypting FW, and it is not accessable AT ALL unless you are on a FW version below 2.5.0 (maybe 2.6.0???), in which case you can use Crank2Unlock to read your code. Otherwise you gotta wait for the exploit I be cooking (or write your own lol). Finally, If you ever wanna install this on your device, either stay on 3.0.2 which is the latest fully-stable version, or jump to 3.1.0 when It comes out since Iâm not releasing my exploit till after that so It wonât be patched :) also hereâs a pic of the current header file, its super broken (Ill star one of your repoâs if you can spot the issues!) but it used to work and it will, and really thatâs all that matters."}]...
|
Title: PlayBrew - Homebrew for the Playdate! by @m Title: PlayBrew - Homebrew for the Playdate! by @mindstormpro3 | Stardance
Devlogs:
Devlog #0 - A quick Recap This is my first devlog for PlayBrew, my Playdate Homebrew, and it is mostly focused on explaining what I have thus far. What is PlayBrew? Playbrew is a homebrew for the playdate game console that enables the user of the device (YOU!) to unlock your consoleâs true potential! You can code payloads, which are C scripts compiled into binary files, and then run them on-device with full low level firmware access (no sandboxing!!!). Possible payloads could be one that enables the bluetooth functionality, one that allows you to set a custom lock screen, and even one for game modding! (I have a whole list of cool ideas that I may share later) The state of things Sooo sadly right now PlayBrew is unfunctional đ⌠So far I have been able to modify the firmware to allow for ACE (arbitrary code execution (also donât worry the games canât access it so no worry of malware :D)) of some C code that gets compiled and appended to the firmware, but I am having issues with the filesystem and am unable to read the actual payloads. The way the arbitrary code runs is by modifying a function pointer to the main FW update loop to run my code, and then at the end of PlayBrewâs code it just returns into the FW update loop and the firmware runs as normal. sooo now whatâs next? Thereâs a couple things I have planned, kinda ranked in order of importance: Getting the FS to work (I am making progress on that rn) Making the payload build system (gonna need help with that lol⌠I hate the C compiler) expanding the API before the full v1 release (I have to manually expose all of the functions from the FW since their addresses can changeâŚ) Get sleep (so basically I havzzzzzzzzzzzzzzzzzzzz) make a way to dump the unlock code (itâs your FW decryption key) make an installer donât get DMCA takedownâed Sign me up! hold up there⌠even If you own a playdate, there are a few different things you need to know ahead of time, and in short, you canât install it. this is because: firmware for the device (specifically the pdfw file in a PlaydateOS.pdos (which is just a zip) file) is encrypted, so you gotta get your device specific key and write or find a tool to decrypt it, and I canât legally share one because of the really dumb law called the DMCA :( PlayBrew is ONLY compatable with rev. B devices (the newer ones) at this time. I donât have a rev. A to test it on but it is possible to port it, I just canât rn You need your unlock code, as required in the first point. The unlock code is a special decryption key used for decrypting FW, and it is not accessable AT ALL unless you are on a FW version below 2.5.0 (maybe 2.6.0???), in which case you can use Crank2Unlock to read your code. Otherwise you gotta wait for the exploit I be cooking (or write your own lol). Finally, If you ever wanna install this on your device, either stay on 3.0.2 which is the latest fully-stable version, or jump to 3.1.0 when It comes out since Iâm not releasing my exploit till after that so It wonât be patched :) also hereâs a pic of the current header file, its super broken (Ill star one of your repoâs if you can spot the issues!) but it used to work and it will, and really thatâs all that matters.
Devlog #1: PROGRESS! To sum it up: the firmware mod is almost done, and I am going to start on the homebrew menu! since the last devlog, I went through 4 iterations on the homebrew loader design: It. 1: The OG design , a patched update loop that runs my homebrew before the update loop begins, with a file open func to read payloads It. 2: same design , but using lower-level uC-fs file IO funcs since the regular ones didnt seem to work when elevated It. 3: New design , this time I patched the LoadPDX() function that loads games/apps to elevate permissions if a system app was being ran (there is an unpatched exploit to install any app as a system app so this route made sense) It. 4: New design a function is placed at the end of the firmware that just contains a single svc #2 , which is the assembly instruction that elevates your permissions and then returns, so that the caller gets elevated (this works because the CPU only will run elevation/permission change functions from firmware code, not loaded code like a game) Iteration #4 is the current iteration and I am actively working to get it⌠well⌠working. The current issue right now is for some reason it seems to crash when I run the homebrew app, but the firmware itself is fine so I am going to try a couple of things....
|
1793534129.184048
|
1794138929.184048
|
|
20494
|
Untitled project by @foxiroll2020 | Stardance
|
foxiroll2020
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Untitled project by @foxiroll2020 | Stardan Title: Untitled project by @foxiroll2020 | Stardance...
|
1793462180.8928635
|
1794066980.8928635
|
|
20495
|
Hangman by @thanEay | Stardance
|
thanEay
|
1
|
17.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-20T20:49:03Z", "hours": 17.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Ready to ship my project! Try it at https://hangman.epin.to This is my hangman project. I put a lot of time into this project, written in Python. While it may look simple, there is a lot of nuance and thought put into it. For example, you can guess single letters, guess entire words, choose a random word to guess, or enter one yourself for a friend to guess. I have been learning Python for a few months and decided that a project like this had just enough complexity that I would learn but not enough that I would give up. Although this project has been completed for months, I procrastinated shipping it until now. I hope that you like it!", "repo": "https://github.com/thanEay/hackclub-hangman", "demo": "https://hangman.epin.to"}]...
|
[{"post_id": 16461, "ts": "202 [{"post_id": 16461, "ts": "2026-06-26T19:59:09Z", "hours": 2.4122, "text": "After much work, it is time to ship my project! Updated demo at hangman.epin.to . This project has taught me a lot about making working projects in Python. I only started learning Python at the beginning of this year, and this is the largest coding project that I have completed so far. It may not seem like a lot, but I put many hours into this code. Much of that time was fun, spent coding the main flow of the code. But eventually, the last few hours of this project went into debugging, trying to catch edge cases, and improved user messaging. So what have I worked on since my last devlog? Mostly implementing a way to disable the counter to play just for fun with infinite guesses. It is accessed by putting an exclamation mark before the mode input (like !m for manual or !r for random). Because no counter is going up, no hangman is displayed. I also changed some player messaging to make things clearer. When a correct letter is guessed, the 1-based location(s) in the word is printed rather than the 0-based indexes that Python uses for its lists. Finally, â!â by itself is rejected as a guess. If it is input, the user will get a message saying that â!â alone is not an acceptable input."}, {"post_id": 15443, "ts": "2026-06-25T03:07:41Z", "hours": 4.1822, "text": "Live demo hosted on Nest at hangman.epin.to . I made lots of progress, as you can probably tell with the amount of time it took. I added functionality for guessing entire words, which took about half of my four logged hours. Also, when the word is guessed correctly, the sprite changes to the man falling off of the gallows and saying âthanksâ. To guess entire words, you put an exclamation mark at the beginning of your answer. Otherwise, only single letters are accepted. For example, to guess âstardanceâ all at once rather than one letter at a time, you would enter â!stardanceâ. If a word guess is incorrect, the counter for tries left goes down one, just like it would for guessing an incorrect letter. I also updated some of the user prompts to make them more clear, as well as printing out all already guessed answers (letters and words) after any letter input (correct or incorrect) or incorrect word guesses so that the player can better guess correct words/letters. The reason that this project, despite its apparent simplicity is taking so long is the little features. For example, I added different messages based on different conditions (Have letters and/or words been guessed? If only one has, change the already guessed printed message to match.) TODO: Add the ability to turn off the counter so that the game can be played without a guess limit."}, {"post_id": 13768, "ts": "2026-06-22T15:52:50Z", "hours": 2.8817, "text": "Sprites added. Sprites are saved as a list of multi-line strings in ascii_sprites.py. As the name implies, the sprites are completely ascii and printable to the terminal. Additionally, now if the word has spaces, the printed characters will contain a space in the given spot. For example, âhack clubâ will be ____ ____ instead of nine unbroken underscores. Letters that have been guessed already are printed out when an incorrect answer is chosen. I might change it to always tell you regardless of an incorrect answer to make it easier to guess. TODO: I need to add the ability to guess an entire word. I would also like to add a sprite change if the player guesses correctly. Maybe the guy would be released from the gallows or something."}, {"post_id": 11730, "ts": "2026-06-19T03:14:35Z", "hours": 1.6522, "text": "Working prototype completed! At this point, all text-related functionality is present. You can enter characters that show up more than once in a word, and it wonât throw errors. I spent the better part of a half hour trying to find out why most times I would enter a letter, it would say that there were none of that letter in the word. This was clearly a bug, as it happened even when entering a letter for a manually chosen word (showing that I wasnât just an abysmal letter guesser). It turned out that the lack of two characters caused my problem. In my check_letter() function, it creates different letter location lists depending on whether there is one or more instances of that letter in the word. The code is like this. def check_letter(word: str, letter: str) -> list: if isinstance(letter, str) and len(letter) == 1: locations = [] if word.count(letter) == 1: locations = [word.find(letter)] elif word.count(letter) > 1: # BUG found here! elif was an if statement for index, character in enumerate(word): if character == letter: locations.append(index) else: locations = [-1] return locations # If letter is not in the word, will result in index of -1 The comment that starts with âBUGâ shows where the problem originated from. Any word with a single instance of a letter returned [-1] because if word.count(letter) > 1 would always override an intended single element list. Now, I need to add hangman sprites that will progress as you choose correct or incorrect answers, probably using ASCII characters."}, {"post_id": 11272, "ts": "2026-06-18T13:07:08Z", "hours": 2.6856, "text": "Last day of school, and even more coding! I have a mostly working prototype that can be seen below. There is no hangman sprite yet, but most of the functionality is here. Main.py has been expanded greatly. Now you can choose the game mode and enter characters. It also displays blank, unknown characters as â_â and shows known characters as their letters, printing again after every input. A major bug that remains is that if a word has two identical letters (like âaâ in Stardance), only one can be input and uncovered. This is due to code that was meant to prevent people from doing the same wrong answer twice, but it also prevents entering the same right answer twice. This is the culprit code. In the looping code (counter does not go up in the current version, it is mostly a placeholder): while counter < 10: user_input = input(\"Enter another letter: \") if user_input.strip().lower() in already_guessed: print(\"You already guessed that letter.\") continue # Goes to next loop In the ask_for_letter() function, only a single instance of a letter is uncovered, even if the letter appears more than once. index = check_letter(word, letter) if index != -1: already_guessed.append(letter) message = f\"{letter} is in the word at index {index}.\" uncovered_indicies.append(index) return index, message check_letter() only returns a single index, which then only uncovers a single letter in the word. I need to fix this by giving the functions the ability to take and return multiple indexes. The image below shows an example of the current code. The word is âcrypticâ, but the last âcâ cannot be selected. Assuming the word doesnât have two of the same letter, when the word is guessed the following message is printed: You guessed the word: {secret_word}. Congratulations! đ"}, {"post_id": 10869, "ts": "2026-06-17T20:30:12Z", "hours": 1.5619, "text": "It is the second to last day of school, and that means a lot of free time to code! I worked on more functions that I will use, and I added docstrings for everything. I have an ask_for_letter() function that will do the heavy lifting for the hangman logic to keep a clean main.py. So far in main.py, I have logic to choose the word. I will expand main.py, but most of the logic will be kept in functions."}, {"post_id": 10414, "ts": "2026-06-17T03:21:09Z", "hours": 1.2764, "text": "I got a great start to this project. I wrote some functions that I will need to call in main.py, specifically one to ask the user for manual or random word choice, one to check the location of a letter in a word, and to choose a random word. I am trying to follow some best practices for Python, like functions in a separate file, docstrings, return type annotations, and descriptive errors. Next, I will finish up some of the major functions and start on main.py."}]...
|
Title: Hangman by @thanEay | Stardance
Devlogs:
I Title: Hangman by @thanEay | Stardance
Devlogs:
I got a great start to this project. I wrote some functions that I will need to call in main.py, specifically one to ask the user for manual or random word choice, one to check the location of a letter in a word, and to choose a random word. I am trying to follow some best practices for Python, like functions in a separate file, docstrings, return type annotations, and descriptive errors. Next, I will finish up some of the major functions and start on main.py.
It is the second to last day of school, and that means a lot of free time to code! I worked on more functions that I will use, and I added docstrings for everything. I have an ask_for_letter() function that will do the heavy lifting for the hangman logic to keep a clean main.py. So far in main.py, I have logic to choose the word. I will expand main.py, but most of the logic will be kept in functions.
Last day of school, and even more coding! I have a mostly working prototype that can be seen below. There is no hangman sprite yet, but most of the functionality is here. Main.py has been expanded greatly. Now you can choose the game mode and enter characters. It also displays blank, unknown characters as â_â and shows known characters as their letters, printing again after every input. A major bug that remains is that if a word has two identical letters (like âaâ in Stardance), only one can be input and uncovered. This is due to code that was meant to prevent people from doing the same wrong answer twice, but it also prevents entering the same right answer twice. This is the culprit code. In the looping code (counter does not go up in the current version, it is mostly a placeholder): while counter < 10: user_input = input("Enter another letter: ") if user_input.strip().lower() in already_guessed: print("You already guessed that letter.") continue # Goes to next loop In the ask_for_letter() function, only a single instance of a letter is uncovered, even if the letter appears more than once. index = check_letter(word, letter) if index != -1: already_guessed.append(letter) message = f"{letter} is in the word at index {index}." uncovered_indicies.append(index) return index, message check_letter() only returns a single index, which then only uncovers a single letter in the word. I need to fix this by giving the functions the ability to take and return multiple indexes. The image below shows an example of the current code. The word is âcrypticâ, but the last âcâ cannot be selected. Assuming the word doesnât have two of the same letter, when the word is guessed the following message is printed: You guessed the word: {secret_word}. Congratulations! đ
Working prototype completed! At this point, all text-related functionality is present. You can enter characters that show up more than once in a word, and it wonât throw errors. I spent the better part of a half hour trying to find out why most times I would enter a letter, it would say that there were none of that letter in the word. This was clearly a bug, as it happened even when entering a letter for a manually chosen word (showing that I wasnât just an abysmal letter guesser). It turned out that the lack of two characters caused my problem. In my check_letter() function, it creates different letter location lists depending on whether there is one or more instances of that letter in the word. The code is like this. def check_letter(word: str, letter: str) -> list: if isinstance(letter, str) and len(letter) == 1: locations = [] if word.count(letter) == 1: locations = [word.find(letter)] elif word.count(letter) > 1: # BUG found here! elif was an if statement for index, character in enumerate(word): if character == letter: locations.append(index) else: locations = [-1] return locations # If letter is not in the word, will result in index of -1 The comment that starts with âBUGâ shows where the problem originated from. Any word with a single instance of a letter returned [-1] because if word.count(letter) > 1 would always override an intended single element list. Now, I need to add hangman sprites that will progress as you choose correct or incorrect answers, probably using ASCII characters.
Sprites added. Sprites are saved as a list of multi-line strings in ascii_sprites.py. As the name implies, the sprites are completely ascii and printable to the terminal. Additionally, now if the word has spaces, the printed characters will contain a space in the given spot. For example, âhack clubâ will be ____ ____ instead of nine unbroken underscores. Letters that have been guessed already are printed out when an incorrect answer is chosen. I might change it to always tell you regardless of an incorrect answer to make it easier to guess. TODO: I need to add the ability to guess an entire word. I would also like to add a sprite change if the player guesses correctly. Maybe the guy would be released from the gallows or something.
Live demo hosted on Nest at hangman.epin.to . I made lots of progress, as you can probably tell with the amount of time it took. I added functionality for guessing entire words, which took about half of my four logged hours. Also, when the word is guessed correctly, the sprite changes to the man falling off of the gallows and saying âthanksâ. To guess entire words, you put an exclamation mark at the beginning of your answer. Otherwise, only single letters are accepted. For example, to guess âstardanceâ all at once rather than one letter at a time, you would enter â!stardanceâ. If a word guess is incorrect, the counter for tries left goes down one, just like it would for guessing an incorrect letter. I also updated some of the user prompts to make them more clear, as well as printing out all already guessed answers (letters and words) after any letter input (correct or incorrect) or incorrect word guesses so that the player can better guess correct words/letters. The reason that this project, despite its apparent simplicity is taking so long is the little features. For example, I added different messages based on different conditions (Have letters and/or words been guessed? If only one has, change the already guessed printed message to match.) TODO: Add the ability to turn off the counter so that the game can be played without a guess limit.
After much work, it is time to ship my project! Updated demo at hangman.epin.to . This project has taught me a lot about making working projects in Python. I only started learning Python at the beginning of this year, and this is the largest coding project that I have completed so far. It may not seem like a lot, but I put many hours into this code. Much of that time was fun, spent coding the main flow of the code. But eventually, the last few hours of this project went into debugging, trying to catch edge cases, and improved user messaging. So what have I worked on since my last devlog? Mostly implementing a way to disable the counter to play just for fun with infinite guesses. It is accessed by putting an exclamation mark before the mode input (like !m for manual or !r for random). Because no counter is going up, no hangman is displayed. I also changed some player messaging to make things clearer. When a correct letter is guessed, the 1-based location(s) in the word is printed rather than the 0-based indexes that Python uses for its lists. Finally, â!â by itself is rejected as a guess. If it is input, the user will get a message saying that â!â alone is not an acceptable input.
Ships:
Ready to ship my project! Try it at https://hangman.epin.to This is my hangman project. I put a lot of time into this project, written in Python. While it may look simple, there is a lot of nuance and thought put into it. For example, you can guess single letters, guess entire words, choose a random word to guess, or enter one yourself for a friend to guess. I have been learning Python for a few months and decided that a project like this had just enough complexity that I would learn but not enough that I would give up. Although this project has been completed for months, I procrastinated shipping it until now. I hope that you like it!...
|
1794023641.4552405
|
1794110041.4552405
|
|
20496
|
LampOS by @aladdin | Stardance
|
aladdin
|
0
|
11.03
|
0
|
[]
|
[{"post_id": 12129, "ts": "202 [{"post_id": 12129, "ts": "2026-06-19T20:21:02Z", "hours": 2.9122, "text": "Devlog #5 | LampOS Morning everyone! I added a settings app, which honestly shouldâve existed a while ago. Itâs got the same sidebar pattern as notes and files (categories on the left, content on the right), split into four sections: appearance, clock, system, and about. Appearance is the fun one â dark/light mode toggle, five accent color swatches, and four wallpaper presets (dots, linen, stripes, plain). Flipping any of these updates the CSS variables on the body in real time, so the whole OS re-themes itself instantly without touching every individual appâs styles. Thatâs the payoff of building everything off CSS variables from day one â paid off here more than I expected. Clock lets you switch between 12-hour and 24-hour format for the topbar clock. System shows live uptime, storage used, and counts for notes/files/events â basically a tiny dashboard pulling from the same localStorage keys the other apps already write to. Threw in a reset-all-data button too, gated behind a confirm so nobody nukes their notes by accident. About is just the boring but necessary stuff â version number, a short blurb, link to say hi. Everything saves to one new localStorage key (lamposSettings) and gets applied on boot, so preferences persist across reloads. Ran into a small bug right after shipping it â the clock format toggle was saving correctly, but the clock display itself was reading from a key that didnât exist, so 24-hour mode silently never worked. Classic âwrote the setter, forgot the getter wasnât hooked upâ moment. Fixed now. Next up: still want to wire notes into the file manager like I said last time. Settings kind of jumped the queue because it felt like a quick win, but thatâs still the bigger structural thing on my list. Thanks for stopping by!"}, {"post_id": 11782, "ts": "2026-06-19T05:26:52Z", "hours": 3.1142, "text": "Devlog #4 | LampOS Alright, back at it! Todayâs focus was two bigger systems: a file manager and a calendar. The file manager was the one I was most excited about. Folders on the left, files on the right, all stored in localStorage. You can create folders, create files inside them, rename, delete â basic but functional. The idea is eventually other apps (notes especially) can plug into this same storage system instead of having their own separate localStorage key, so everything in the OS lives in one place. Not there yet, but the foundationâs built. The calendar came together pretty cleanly after the file manager groundwork. Monthly grid view, click a date to see/add events, little dot indicator on days that have events. Had to get the date math right for the first-day offset so the grid lines up correctly with the right day of the week, that took a couple tries. Both apps follow the same folder/sidebar pattern as notes and movies at this point, so the OS is starting to feel a lot more cohesive instead of just a bunch of separate apps bolted together. Tomorrow I think I want to actually wire notes into the file manager like I mentioned, so they share the same underlying storage instead of being two separate systems. Thanks for stopping by!"}, {"post_id": 11634, "ts": "2026-06-18T23:06:29Z", "hours": 2.0236, "text": "Devlog #3 | LampOS Evening all! Big one today. Added three things: an AI chatbot (lampai), a notes app, and a calculator. The notes app was straightforward â sidebar list of notes, click to edit, autosaves to localStorage as you type. Added a little âsavedâ indicator that fades in and out so thereâs some feedback when itâs actually persisting. The calculator was fun, just standard four-function stuff with a clean grid layout. Took a bit to get the +/- and % logic right but nothing major. The chatbot, though. That was a whole journey. Wanted lampai to feel like a small AI living inside the OS, not just a generic chat widget. Getting the API connection working took way longer than expected â kept hitting CORS issues trying to call the API directly from the browser, which makes sense in hindsight since you canât expose an API key client-side. Ended up setting up a Cloudflare Worker as a proxy so the key stays server-side and the frontend just talks to my worker URL instead. A few false starts along the way (typos in the worker code, wrong response parsing, the usual) but got it stable by the end of the night. Now lampai actually responds and keeps conversation history during the session. Feels like the OS has a little bit of life in it now. Thanks for stopping by!"}, {"post_id": 11400, "ts": "2026-06-18T17:43:37Z", "hours": 1.9128, "text": "Devlog #2 | LampOS Hey, hope everyoneâs doing well! First real apps today. Started with a contact page since it felt like the easiest win â just a little card with email, discord, and instagram, click any row to copy it to clipboard. Simple, but satisfying to see it work. Then I built out the movies section, which ended up being more fun than I expected. Sidebar with a list of movies, click one and it loads the details on the right â title, year, rating, my thoughts on it. Right now itâs just hardcoded data (Spirited Away, Grand Budapest Hotel, Whiplash), but the structure is there to make it dynamic later if I want. Ran into a small CSS issue where the sidebar entries werenât highlighting correctly when active â turned out I had a typo, movies-entry instead of movie-entry in one spot. Classic. Caught it eventually. Feels good having actual content in the OS now instead of just an empty shell. Next up I want to add something more interactive. Thanks for stopping by!"}, {"post_id": 10881, "ts": "2026-06-17T20:48:57Z", "hours": 1.0628, "text": "Devlog #1 | LampOS Whatâs good everyone! Today was mostly about getting LampOS off the ground. I followed a setup guide to get the basic shell working â windows, dragging, the boot screen, all that. Nothing too crazy, but itâs the kind of foundational stuff that everything else depends on, so I wanted to get it right before building on top of it. The window dragging took a minute to get smooth. My first pass had the windows jittering whenever you moved the mouse too fast, turns out I was tracking the delta wrong. Fixed it by recalculating initialX and initialY on every mousemove instead of just once at the start. I also added the little boot animation with the logo and progress bar, mostly because it felt right for something calling itself an âOS.â Small detail but it makes the whole thing feel more like a real product and less like a webpage. By the end of the day I had a working desktop with draggable windows, a topbar with a live clock, and basically nothing else â but it was a real foundation. Tomorrow I want to start adding actual apps. Thanks for stopping by!"}]...
|
Title: LampOS by @aladdin | Stardance
Devlogs:
De Title: LampOS by @aladdin | Stardance
Devlogs:
Devlog #1 | LampOS Whatâs good everyone! Today was mostly about getting LampOS off the ground. I followed a setup guide to get the basic shell working â windows, dragging, the boot screen, all that. Nothing too crazy, but itâs the kind of foundational stuff that everything else depends on, so I wanted to get it right before building on top of it. The window dragging took a minute to get smooth. My first pass had the windows jittering whenever you moved the mouse too fast, turns out I was tracking the delta wrong. Fixed it by recalculating initialX and initialY on every mousemove instead of just once at the start. I also added the little boot animation with the logo and progress bar, mostly because it felt right for something calling itself an âOS.â Small detail but it makes the whole thing feel more like a real product and less like a webpage. By the end of the day I had a working desktop with draggable windows, a topbar with a live clock, and basically nothing else â but it was a real foundation. Tomorrow I want to start adding actual apps. Thanks for stopping by!
Devlog #2 | LampOS Hey, hope everyoneâs doing well! First real apps today. Started with a contact page since it felt like the easiest win â just a little card with email, discord, and instagram, click any row to copy it to clipboard. Simple, but satisfying to see it work. Then I built out the movies section, which ended up being more fun than I expected. Sidebar with a list of movies, click one and it loads the details on the right â title, year, rating, my thoughts on it. Right now itâs just hardcoded data (Spirited Away, Grand Budapest Hotel, Whiplash), but the structure is there to make it dynamic later if I want. Ran into a small CSS issue where the sidebar entries werenât highlighting correctly when active â turned out I had a typo, movies-entry instead of movie-entry in one spot. Classic. Caught it eventually. Feels good having actual content in the OS now instead of just an empty shell. Next up I want to add something more interactive. Thanks for stopping by!
Devlog #3 | LampOS Evening all! Big one today. Added three things: an AI chatbot (lampai), a notes app, and a calculator. The notes app was straightforward â sidebar list of notes, click to edit, autosaves to localStorage as you type. Added a little âsavedâ indicator that fades in and out so thereâs some feedback when itâs actually persisting. The calculator was fun, just standard four-function stuff with a clean grid layout. Took a bit to get the +/- and % logic right but nothing major. The chatbot, though. That was a whole journey. Wanted lampai to feel like a small AI living inside the OS, not just a generic chat widget. Getting the API connection working took way longer than expected â kept hitting CORS issues trying to call the API directly from the browser, which makes sense in hindsight since you canât expose an API key client-side. Ended up setting up a Cloudflare Worker as a proxy so the key stays server-side and the frontend just talks to my worker URL instead. A few false starts along the way (typos in the worker code, wrong response parsing, the usual) but got it stable by the end of the night. Now lampai actually responds and keeps conversation history during the session. Feels like the OS has a little bit of life in it now. Thanks for stopping by!
Devlog #4 | LampOS Alright, back at it! Todayâs focus was two bigger systems: a file manager and a calendar. The file manager was the one I was most excited about. Folders on the left, files on the right, all stored in localStorage. You can create folders, create files inside them, rename, delete â basic but functional. The idea is eventually other apps (notes especially) can plug into this same storage system instead of having their own separate localStorage key, so everything in the OS lives in one place. Not there yet, but the foundationâs built. The calendar came together pretty cleanly after the file manager groundwork. Monthly grid view, click a date to see/add events, little dot indicator on days that have events. Had to get the date math right for the first-day offset so the grid lines up correctly with the right day of the week, that took a couple tries. Both apps follow the same folder/sidebar pattern as notes and movies at this point, so the OS is starting to feel a lot more cohesive instead of just a bunch of separate apps bolted together. Tomorrow I think I want to actually wire notes into the file manager like I mentioned, so they share the same underlying storage instead of being two separate systems. Thanks for stopping by!
Devlog #5 | LampOS Morning everyone! I added a settings app, which honestly shouldâve existed a while ago. Itâs got the same sidebar pattern as notes and files (categories on the left, content on the right), split into four sections: appearance, clock, system, and about. Appearance is the fun one â dark/light mode toggle, five accent color swatches, and four wallpaper presets (dots, linen, stripes, plain). Flipping any of these updates the CSS variables on the body in real time, so the whole OS re-themes itself instantly without touching every individual appâs styles. Thatâs the payoff of building everything off CSS variables from day one â paid off here more than I expected. Clock lets you switch between 12-hour and 24-hour format for the topbar clock. System shows live uptime, storage used, and counts for notes/files/events â basically a tiny dashboard pulling from the same localStorage keys the other apps already write to. Threw in a reset-all-data button too, gated behind a confirm so nobody nukes their notes by accident. About is just the boring but necessary stuff â version number, a short blurb, link to say hi. Everything saves to one new localStorage key (lamposSettings) and gets applied on boot, so preferences persist across reloads. Ran into a small bug right after shipping it â the clock format toggle was saving correctly, but the clock display itself was reading from a key that didnât exist, so 24-hour mode silently never worked. Classic âwrote the setter, forgot the getter wasnât hooked upâ moment. Fixed now. Next up: still want to wire notes into the file manager like I said last time. Settings kind of jumped the queue because it felt like a quick win, but thatâs still the bigger structural thing on my list. Thanks for stopping by!...
|
1793501835.6735241
|
1794106635.6735241
|
|
20497
|
ScreenExtend by @epiccodewizard | Stardance
|
epiccodewizard
|
2
|
129.0
|
985
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-29T04:58:19Z", "hours": 74.0, "multiplier": 12.07, "payout": 827, "blessing": "neutral", "text": "Initial second release for ScreenExtend! Please give feedback and read the devlogs; theyâre detailed and describe the project a lot better than here. The website https://screenextend.app/ quickly summarizes it.", "repo": "https://github.com/ScreenExtend/ScreenExtend", "demo": "https://screenextend.app/"}, {"ship_num": 2, "ts": "2026-07-01T23:47:06Z", "hours": 55.0, "multiplier": 15.76, "payout": 158, "blessing": "neutral", "text": "Initial release for ScreenExtend! Please give feedback and read the initial devlog (shorter one here, longer one at https://github.com/ScreenExtend/ScreenExtend/blob/main/DEVLOG.md ) for detailed information.", "repo": "https://github.com/ScreenExtend/ScreenExtend", "demo": "https://screenextend.app/"}]...
|
[{"post_id": 60703, "ts": "202 [{"post_id": 60703, "ts": "2026-09-03T08:05:38Z", "hours": 9.5622, "text": "One step closer to finally shippingâŚor so I hope. I speedran shipping this next feature, so it took a lot of time. This feature is mainly for myself. I have an old Mac (running 10.13 from 2017, really old I get itttt). I want my app to run on there, but it currently only supports 10.15+. Hence, I went down a funny rabbit hole in an attempt to add support. 33. Cleaning up dylib signature lookups at run time One of the key challenges I faced throughout development was how to have a unified codebase for multiple API versions. I decided that instead of version-gating APIs and guessing which beta/normal versions they would be accessible on, Iâd test for APIs at run time. I changed VideoToolbox to use this logic: it would attempt to set/use APIs and variables available at higher runtimes, but would work fine without them and have fallbacks. This ensured both legacy and modern systems functioned well. 34. Airplay automationsâŚ? As I was doing competitor research, I noticed many of the other apps supported Mac 10.13-10.15 as well as 10.15+, while mainly only supported 10.15+. Essentially, they started a fake Airplay server, had the Mac connect it, and set the display mode to âUse as separate displayâ. This would create a virtual display that the app would then use for its own functions. As ScreenExtend requires its own display on older machines, similar to this, where CGVirtualDisplay isnât an option, I decided to use this method. I had my app automate opening the Airplay menu and connecting as well, in addition to running the fake server. Most of the process was straightforward, especially due to the abundance of fake Airplay server implementations online and my own experience with apps like LonelyScreen. The one issue of this approach is that only one display can be connected at a time, so any tertiary devices wanting to connect have to wait their turn. I guess the only option is to by a new mac then⌠35. Client UI update cleanliness fixes Due to the one device restriction, I implemented a separate page that would be served if the display slot was being used up. It would be coupled with a short message explaining the consequences of the older Mac version. There were also bugs related to session teardown (keyboard still being locked, video stream still active in the background, etc) that I quickly squashed after finding them. Soooo in hindsight, I prolly shouldâve bumped this up to 0.6.0, but I left it at 0.5.4. Oh well, Iâll increment the version by next release. Only a few more features to go on the feature list before hitting v1 and shipping!!!"}, {"post_id": 58576, "ts": "2026-08-31T01:22:07Z", "hours": 12.0222, "text": "Oh my lord, I keep forgetting to write devlogs every 10 hours and am losing hours on each one. Nevertheless, I finally finished audio work! Plus some other things like running claude security agents on the code base and patching stupid vulnerabilities. Hereâs how the week went: 28. HiDPI and Mac Issues Whenever I use my Mac with ScreenExtend, the stream looks blurry due to Macs having HiDPI screens. I fixed this by adding basic HiDPI scaling on Windows. The UI has a DPR slider based on autodetected values. This DPR is multiplied by the screen resolution for a shaper display. One issue that arose with the new displays was the fact that the display would randomly not scale properly, so the task bar and apps would appear tiny. To mitigate this, I reapplied all display settings after resolution changes and a timeout. 29. AUDIO WORKS!!!! For the longest time, I tried getting audio to work. On Windows, the process was straightforward: a WASAPI loopback system audio capture session. I wanted to build my own custom driver to capture audio faster, but this would be too expensive to deploy. I read other Rust implementations and quickly wrote the code. On the other hand, Mac was a whole different issue. On older versions of Mac, system audio recording is not supported. Hence, for Macs below 13.0, I wrote a custom audio driver. I didnât have a clue about implementing an AudioServerPlugIn on Mac, but worked out the specifics by looking at the Blackhole audio driver. I did have to proxy physical volume buttons to work (i.e. I listen for taps and change the audio level within the driver). For older Macs, I used ScreenCaptureKit with an extra audio flag. This was a simple fix to capture audio. On even newer Macs, thereâs a Process Tap API to record system audio with low latency. Once again, I didnât have much difficulties implementing these due to the abundance of documentation. 30. Streaming Audio over WebRTC (with A/V sync) When sending video and audio separately, the two are prone to fall out of sync, so watching movies or videos is difficult. To mitigate these issues, I wrote an A/V sync host clock. This packages the time on the host clock to audio samples and video frames, such that they can be reconstructed and coupled on the receiving end. On the browser side, I began by implementing a basic audio streamer with an audio element. However, similar to video, thereâs always a faster method possible. I used the AudioDecoder class from WebCodecs to implement a worklet class and jitterbuffer. In simple terms, this would decode audio on a separate thread, like WebCodecs prefers, and send the audio back to be played to the user. 31. Windows Video Encoding Speedups I made a few encoding speedups on Windows targets: The NVENC capture encode system uses a texture ring implementation: a pool of 3-5 encoder instances paired with a frame queue, allowing multiple frames to be encoded concurrently BGRA encoding is done directly in the library instead of using a third-party implementation Unchanged frames in DXGI capture are not encoded again, reducing CPU load 32. Mac Video Encoding Speedups I made a few encoding speedups on Mac targets: Request LatencyCritical activity for the session to ensure App Nap and other sleep measures donât affect the thread Analogous to DXGI, skip encoding when CGDisplayStream reports no dirty rects Not an encoding speedup, but preferring 5 GHz for Mac hosted networks to ensure higher speeds Lotta stuff done this week, am I right? I made lots of progress and finished the bulk of my features, although Linux support is still in the works. Iâll make the 1.0.0 release soon and start a Stardance ship as well. Iâll likely add Linux support after 1.0.0, as I need to research EVDI and the WSL display compositor, as well as other minor tweaks for Windows/Mac. See yâall in the next devlog!"}, {"post_id": 54119, "ts": "2026-08-24T22:53:29Z", "hours": 12.6531, "text": "I speedran shipping a buncha featuresâŚin the span of a few days. I logged a copious amount of hours on Hackatime building random stuff. I tried some things with recording system audio and building a driverâŚthose didnât go the best, but Iâll cover that in the next devlog. Here are the main changes this week: 24. Even more quality of life changes Compared to last time, I wanted the user experience to improve even more. Specifically, for the Windows client, a custom display driver is required. On Macs, the functionality I need is built in, so none is required. However, uninstalling this display driver used to be a pain for users. Now, I bundled it as part of the uninstall script. I wasnât sure how to do this, but Tauri has many useful guides and issues opened regarding custom WiX/NSIS code. When the window isnât focused, join and leave notifications are toasted. This allows the user to stay informed even when the app isnât open. Basic feature but very useful. Iâd often get annoyed that I needed to keep re-entering the password to log in to a previously connected device. Hence, I added auto-join for devices based on their IP. This ensures that commonly connected devices can save time when reconnecting. 25. Onboarding screens The app is intuitive to useâŚor so I thought? Some of my beta testers were confused as to the various features and how to use the interface. Hence, I used NextStepjs to add onboarding components. This would dim the UI and only highlight the component being displayed, along with a message next to it. I liked the styles of NextStepjs a lot, so I chose it. There were some issues regarding window resize, so I made the onboarding exit and reopen to the last step when the window is resized. This way, the positioning of elements was forcefully recalculated. 26. Random security fixes My app had various vulnerabilities scattered throughout, so I ran a vulnerability Claude skill and patched some holes. The main issues fixed were: Checksums of bundled DLLs and resources are checked before being pushed to GitHub Actions Tauri CSP and allow list are actually enforced instead of being set to allow all TLS cert used for hosting the HTTPS domain has more secure file system permissions to reduce unwanted tampering of files Devices are trusted by a uniquely generated token, not by IP, to decrease the chance of impersonators 27. Command-line interface A majority of the time on this devlog was spent on the CLI. It wasnât that hard (from a technical perspective), mainly just translating a lot of the UI code into Tauri CLI commands and mapping them correctly in the generated JSON file. One of the harder things to figure out was setting up cross-thread AppState, when the app wasnât exactly runningâŚturned out I just had to move the initialization command to before the window is created, so it would run inside both CLI and GUI modes. To present the QR codes better. I used qr2term to display the QR codes. By default, all logging is hidden. This turns ScreenExtend into a clean CLI mimicking the GUI. Hoorah! Thatâs it for this devlog. Not much to conclude, but plenty more features coming. Stay tuned!"}, {"post_id": 51902, "ts": "2026-08-21T20:12:46Z", "hours": 10.3639, "text": "Oh my lordâŚI crammed a lot of features into this week. I have yet to do proper audits of the codebase as a whole, specifically related to latency optimizations. I added a lot more code that affects the WebRTC pipeline, but I at least got the core features working. 20. Automatic updates For a while, the app relied on manual updating. It would check the latest version on Github, but users would have to go to the website, download the installer, uninstall the current version, and reinstall the newer version. This also messed up config and was a huge pain. Hence, I generated my own signing keys and used the Tauri updater plugin to automatically update apps. When the app is first launched and if an update is available, it automatically downloads and installs it without any user action. To make this more robust, I added a progress bar while downloading the update. On Windows specifically, the app must be shut down and restarted, so a blocking modal prevents devices from joining till this is done. I originally made this modal manually, but switched to using AlertDialog from ShadCN. Another issue I faced was the latest.json manifest. As I used custom filenames when downloading and installing updates, I had to manually patch the JSON. I learned a lot about the Tauri updater Github action through this, as I had to figure out how Tauri generated build filenames and how I could safely update them. 21. Quality of life for client devices I finished QOL fixes on the client side: Remember past devices to quickly import preferences or ban devices (all config saving is IP-based) Warn if the user is attempting to connect from the same device (this app is a remote control tool, but you canât exactly remote control yourself) If the screen orientation changes, the virtual display is updated accordingly using CSS media queries to ensure a seamless experience A no fullscreen mode was added so users could quickly switch apps and maintain productivity 22. Quality of life for host devices I converted all in-app modals and error messages to JSON. This allowed me to add i18n language support, so I could easily translate my app to other languages. To detect and ensure only a single instance of the app was running, I previously used a file lock. However, there was an issue with MSI builds falsely detecting a file lock and not opening. I switched to a basic TCP model for IPC so that multiple processes running can figure out which was there first and shut down the others. 23. More more more Mac features! Iâve always felt a bit sad for my Mac users. I donât have a Mac to test on, so I keep borrowing my dadâs Mac, which results in insanely slow development times. Nevertheless, I made some serious progress this week. The biggest thing was a simpler installation process. Many users would complain that they didnât remember if theyâre on Intel or Apple Silicon, so I now distribute a universal DMG. In terms of the app itself, I added a permissions check for screen recording and input injection. It would run a live test of screen capture or key input to see if the app actually had permissions; therefore, down the road it wouldnât cause issues. I initially tried to do a soft check without an actual test (i.e., read the settings app), but this didnât work. The only foolproof way was to call the API itself. The biggest feature by far was adding Mac input injection. Using accessibility APIs and a charmap similar to Windows, it would inject input onto the Mac screen. I could remotely log in from my Chromebook and get a lot of work done. I mirrored the structure and code on the Windows input injection pipeline, so no major difficulties here. Thatâs it for this week! Lotta stuff added, especially for the Mac users. I have a long list of features to continue building, specifically regarding easier Windows uninstall processes, onboarding, and an overall better UX. See you soon!"}, {"post_id": 39065, "ts": "2026-08-01T19:07:47Z", "hours": 9.8208, "text": "I had so much fun at the conference in San Francisco! I met a lot of cool people who gave me advice on the app, although I didnât see the downloads spike đ. I primarily began working on a SW encoder and other miscellaneous changes: 17. Remote control toggle Sometimes, the user doesnât want a client to have remote control access. Although the purpose of the app is to have remote control, it is useful to disable this feature. On the frontend, I added a toggle switch that enables or disables the remote control backend. I was debating whether WebRTC negotiation was required as well, but decided to do so in the end. The remote control used data channels, so an unused data channel would result in slightly lower latency. Renegotiation ensured the stream stayed as efficient as possible without sending redundant data. 18. Update checking In order for current users to access newer versions, I wanted to add an update functionality. Iâm not using Tauriâs update plugin just yet, so I run a simple check. The app, on startup, checks the latest release tag on GitHub. If itâs not equal to the current version (rollback or higher version), the user is prompted to download the newer version. Automatic updates will come next. 19. The big boy: software encoding This oneâs been a long time coming. A lot of machines like VMs or computers with a weird setup just donât have a working hardware encoder (Intel/AMD/Nvidia), and until now that meant the app straight up didnât work there. So I built a full CPU-only x264 fallback. For the pipeline, the frames come as raw BGRA bytes that the other supporters already encoded. They must be converted to I420 before going to libx264, whose build I pulled from OBS. As a side note, the DLL is bundled with the app at runtime to ensure no missing dependencies. As with any encoder, the rate control is ABR with a tight VBV, as well as an infinite GOP. Besides the technical jargon, this just means latency is the north star and nothing else matters. The whole software variant is added to the encoder vendor enum, and wired into the fallback chain: if NVENC fails, try Intel; if Intel fails, fall back to software before giving up entirely. Thereâs also a manual override if someone really prefers software encoding, but this is not the default. Thereâs a big CPU cost compared to hardware encoding, so itâs very much a last resort and only kicks in if absolutely no GPU encoders are available. But âlast resort that worksâ beats âdoesnât work at all.â Thatâs it for this week! I plan to have some smaller quality-of-life changes and better updates coming soonâŚ"}, {"post_id": 34237, "ts": "2026-07-24T19:29:18Z", "hours": 9.1139, "text": "Sooooo this devlog is mostly comprised of website changes. I have a conference in San Francisco and wanted to polish up the app before publishing. Here are the main changes I made: 13. Random chores and updating the website I absolutely love shadcn-ui, but so do AI models. In past reviews by stardance raters, as well as family and friends, they pointed out the website looked AI-generated. Hence, I decreased the number of gradients and added basic animations to make the site feel more alive. This was a first for me to implement animations, but the Tailwind docs made it quite simple. I used a specific code-like font instead of the generic fonts I had and tidied up CSS classes. The biggest change was adding a blurred-geometric background for a nicer feel. 14. Redesigning the website completely I felt it was better to update the website as a whole, so I changed up the user interface. When I tested the app with real users, they complained that they didnât know how to actually use the app. I changed the hero design to have clearer text and added an SVG-animation component showing how the site actually works. The feature section stayed the same, but there was a highlights grid (inspo https://cider.sh/ ) to highlight the main features. The FAQ was shortened to my liking, and I pulled some utilities from Tailwind for animations. In terms of images, I updated the images of the app featured on the website and cleaned up some of the dimensions related to that CSS. The old homepage still lives inside OldHome() but isnât used anymore. 15. Tidying up the README and build workflows I edited the README to remove redundant information and make it more developer-focused. I also updated some information regarding GPU builds. For the build workflow, I ensured it would only run if the commit ended in ârebuildâ. This ensures unnecessary build minutes are not spent on small changes not requiring a full rebuild. 16. Wake lock API fallback This app aims to support all devices, but older devices haveâŚfunny APIs to say the least. For WebRTC, I implemented the legacy encoded streams API. However, the device would still turn off for seemingly no reason while the video was playing. On older devices, the wake lock API is not supported. However, thereâs a unique workaround for this: any video element playing on the webpage will keep the screen from dimming. Hence, I used the NoSleep library to create an off-screen 1-second video element that keeps looping, ensuring the display doesnât go dark. Some very fun stuff with browsers. Thatâs it for this devlog! Mostly minor changes, but the next one will have better SW encoding support among other changes. Stay tunedâŚ"}, {"post_id": 28772, "ts": "2026-07-15T08:02:33Z", "hours": 10.7358, "text": "I met with some friends to discuss my appâŚand realized I gotta lock in with the features. Among the various topics we discussed like the difficult UI or lack of automatic updates, they really wanted remote control features. So, I set out to make the remote display something I can actually touch, click, and type into. And patching some other bugs along the way. 9. Remote input This is the main headline feature. Streaming pixels one way was solved; now the client had to send input back up the wire and have the host replay it as if it came from real hardware. Host side (Windows). A new input backend injects events through a synthetic pointer device , so mouse, touch, and pen all seem real as opposed to faked mouse moves. The synthetic device can execute touch or mouse movements from the tablet client. macOS and Linux backends are stubbed and will come later (trust me bro). The wire. This side had to be optimized for dead-low latency like the rest of the project. Instead of passing strings or using some wrapper library, I made my own binary protocol (a dedicated protocol module) serialized over WebRTC data channels , not the media path. Client-side input.js captures keyboard, mouse, pointer (touch/pen), wheel, clipboard, and drag-drop and ships them across. The code basically catches every single frontend input event and forwards all those events (20+)! The routing is latency-first, same as everything else, with three different paths. fast-path events (pointer moves, wheel) take an unreliable channel , where a dropped packet is cheaper than a late one, while clicks, keys, and clipboard take the reliable channel where every event must land exactly once. Itâs not that big of a deal if one small mouse delta doesnât go through, but it definitely is a big deal if a click doesnât go through. 10. Browser compatibility detections Not every browser can do WebCodecs, secure contexts, or the input paths above. Rather than fail silently, I added a compatibility check on both the browser and client up front. It shows compatibility modals with per-feature lists to ensure the user knows whatâs going on. 11. Some more small fixes I added two quality-of-life additions: avatars (upload custom profile pictures) and zoom controls (ctrl/cmd +/-). 12. Encoders that donât explode when funny stuff happens Oh my godâŚone of the biggest issues by far. When I ran the NVIDIA encoder at high FPS, it didnât crash. However, the Intel Quick Sync encoder would arbitrarily crash at high FPS and wouldnât give a reason why. I audited a buncha different parts of my code and eventually found that FPS was the issue, not resolution or low-latency flags. Hence, I added a binary search that probes the hardware for its true maximum supported fps and clamps to it before the encoder can choke. Essentially, I ask the encoder âcan you do 1920x1080 at 240 fps?â â> ânoâ â> âwhat about 120 fps?â â> âyesâ â> âwhat about 180 fps?â. This keeps repeating till the max FPS is found and streamed to the client. Rounding out the release, I made a variety of different UI fixes like the modal fixes , backdrop overlap, a stray uninstall-modal backdrop, and cloud reconfig errors . More progress to come!"}, {"post_id": 20389, "ts": "2026-07-01T23:35:58Z", "hours": 54.7942, "text": "ScreenExtend Devlog: Building the Rust Engine Under a Wireless Second Monitor TL;DR ScreenExtend turns any device with a browser into a real, wireless extended monitor for a Windows host, no client app and no cables (it began so my brother could use his iPad for notes at debate tournaments). Scan a QR code and the host spins up a real virtual display, streamed over WebRTC with hardware H.264. The React/TS control UI existed before; everything else (Rust core, GPU pipeline, WebCodecs client, cloud relay) was built from scratch , always latency-first, quality-second. 1. The spine: Tauri + a typed RustâTS bridge tauri-specta exports a fully-typed src/lib/bindings.ts for commands (TSâRust) plus typed events (RustâTS): devices, network, cloud status, logs. A code-generated bridge beats maintaining one by hand. Let the code write itself! 2. Virtual displays: faking a real monitor Each client gets its own virtual display the OS treats as real hardware, a true second screen, not mirroring. On join the host creates one sized to the client , forces extend topology, then captures it once attached. On Windows a signed IDD driver installs at runtime (via nefconc + certutil ), and it tears down cleanly on leave. 3. First light: WebRTC + WHEP + H.264 The media path is WebRTC (real-time, in every browser). Signaling is WHEP : the client POSTs an SDP offer, the host answers in-response, no signaling server. Codec is H.264 , universal hardware decode on clients and encode (NVENC/QSV/AMF) on hosts. The first release streamed NVENC to a plain <video> ; it worked but was laggy. It binds HTTP + HTTPS (self-signed via rcgen ) , since WebCodecs needs a secure context. 4. The pipeline: capture â encode â broadcast Capture is Windows Graphics Capture (later a custom fork; DXGI Desktop Duplication fallback), with a repeater thread for idle keepalive/IDRs and transient-stall tolerance. 5. Going vendor-specific: the part that made it fast Generic captureâCPU-copyâencode is slow everywhere; the win: keep the frame on the GPU from capture to bitstream. Per vendor: NVENC (NVIDIA): no SDK linked (API dynamically loaded ); zero-copy writes capture into a shared D3D11 texture behind a keyed mutex, else a CPU bridge. Intel QSV/oneVPL: same-adapter capture+encode fuses the downscale into the VPP pass (BGRAâNV12 + resize in one shot). macOS (VideoToolbox): ScreenCaptureKit (12.3+, CGDisplayStream fallback) via objc2 runtime interop only , so one binary loads on every macOS version, same IOSurface zero-copy. 6. The client: WebCodecs over <video> Fast path: an RTCRtpScriptTransform feeds a worker VideoDecoder ( optimizeForLatency: true ) onto an OffscreenCanvas , latency hints zeroed. A <video> fallback covers missing WebCodecs or stalls. It also feels like a monitor: fullscreen + input/wake locks, /leave beacon on exit. 7. Adaptive bitrate, sessions & security A BWE driver reads getStats every 250ms, pushing a smoothed bitrate into the encoder. Changing settings triggers in-place renegotiation (a reconfig/kick epoch the client polls) with no display teardown. Each host is gated by a session ID + 6-digit OTP ( OtpLimiter lockout); every device is isolated, over HTTPS + DTLS/SRTP. 8. Networking + status (v0.2.3) Same-network is direct, no servers. Offline mode stands up an ad-hoc hosted network , no infrastructure needed. Cross-network adds a cloud relay (WebSocket to session.screenextend.app ) tunneling signaling while media stays P2P; a self-hosted TURN server covers hard NATs. A logbus feeds an in-app terminal. Working today: Windows/macOS hosts, per-vendor GPU encode, per-device displays, adaptive bitrate, OTP sessions, offline mode, and cloud relay."}]...
|
Title: ScreenExtend by @epiccodewizard | Stardance Title: ScreenExtend by @epiccodewizard | Stardance
Devlogs:
ScreenExtend Devlog: Building the Rust Engine Under a Wireless Second Monitor TL;DR ScreenExtend turns any device with a browser into a real, wireless extended monitor for a Windows host, no client app and no cables (it began so my brother could use his iPad for notes at debate tournaments). Scan a QR code and the host spins up a real virtual display, streamed over WebRTC with hardware H.264. The React/TS control UI existed before; everything else (Rust core, GPU pipeline, WebCodecs client, cloud relay) was built from scratch , always latency-first, quality-second. 1. The spine: Tauri + a typed RustâTS bridge tauri-specta exports a fully-typed src/lib/bindings.ts for commands (TSâRust) plus typed events (RustâTS): devices, network, cloud status, logs. A code-generated bridge beats maintaining one by hand. Let the code write itself! 2. Virtual displays: faking a real monitor Each client gets its own virtual display the OS treats as real hardware, a true second screen, not mirroring. On join the host creates one sized to the client , forces extend topology, then captures it once attached. On Windows a signed IDD driver installs at runtime (via nefconc + certutil ), and it tears down cleanly on leave. 3. First light: WebRTC + WHEP + H.264 The media path is WebRTC (real-time, in every browser). Signaling is WHEP : the client POSTs an SDP offer, the host answers in-response, no signaling server. Codec is H.264 , universal hardware decode on clients and encode (NVENC/QSV/AMF) on hosts. The first release streamed NVENC to a plain <video> ; it worked but was laggy. It binds HTTP + HTTPS (self-signed via rcgen ) , since WebCodecs needs a secure context. 4. The pipeline: capture â encode â broadcast Capture is Windows Graphics Capture (later a custom fork; DXGI Desktop Duplication fallback), with a repeater thread for idle keepalive/IDRs and transient-stall tolerance. 5. Going vendor-specific: the part that made it fast Generic captureâCPU-copyâencode is slow everywhere; the win: keep the frame on the GPU from capture to bitstream. Per vendor: NVENC (NVIDIA): no SDK linked (API dynamically loaded ); zero-copy writes capture into a shared D3D11 texture behind a keyed mutex, else a CPU bridge. Intel QSV/oneVPL: same-adapter capture+encode fuses the downscale into the VPP pass (BGRAâNV12 + resize in one shot). macOS (VideoToolbox): ScreenCaptureKit (12.3+, CGDisplayStream fallback) via objc2 runtime interop only , so one binary loads on every macOS version, same IOSurface zero-copy. 6. The client: WebCodecs over <video> Fast path: an RTCRtpScriptTransform feeds a worker VideoDecoder ( optimizeForLatency: true ) onto an OffscreenCanvas , latency hints zeroed. A <video> fallback covers missing WebCodecs or stalls. It also feels like a monitor: fullscreen + input/wake locks, /leave beacon on exit. 7. Adaptive bitrate, sessions & security A BWE driver reads getStats every 250ms, pushing a smoothed bitrate into the encoder. Changing settings triggers in-place renegotiation (a reconfig/kick epoch the client polls) with no display teardown. Each host is gated by a session ID + 6-digit OTP ( OtpLimiter lockout); every device is isolated, over HTTPS + DTLS/SRTP. 8. Networking + status (v0.2.3) Same-network is direct, no servers. Offline mode stands up an ad-hoc hosted network , no infrastructure needed. Cross-network adds a cloud relay (WebSocket to session.screenextend.app ) tunneling signaling while media stays P2P; a self-hosted TURN server covers hard NATs. A logbus feeds an in-app terminal. Working today: Windows/macOS hosts, per-vendor GPU encode, per-device displays, adaptive bitrate, OTP sessions, offline mode, and cloud relay.
I met with some friends to discuss my appâŚand realized I gotta lock in with the features. Among the various topics we discussed like the difficult UI or lack of automatic updates, they really wanted remote control features. So, I set out to make the remote display something I can actually touch, click, and type into. And patching some other bugs along the way. 9. Remote input This is the main headline feature. Streaming pixels one way was solved; now the client had to send input back up the wire and have the host replay it as if it came from real hardware. Host side (Windows). A new input backend injects events through a synthetic pointer device , so mouse, touch, and pen all seem real as opposed to faked mouse moves. The synthetic device can execute touch or mouse movements from the tablet client. macOS and Linux backends are stubbed and will come later (trust me bro). The wire. This side had to be optimized for dead-low latency like the rest of the project. Instead of passing strings or using some wrapper library, I made my own binary protocol (a dedicated protocol module) serialized over WebRTC data channels , not the media path. Client-side input.js captures keyboard, mouse, pointer (touch/pen), wheel, clipboard, and drag-drop and ships them across. The code basically catches every single frontend input event and forwards all those events (20+)! The routing is latency-first, same as everything else, with three different paths. fast-path events (pointer moves, wheel) take an unreliable channel , where a dropped packet is cheaper than a late one, while clicks, keys, and clipboard take the reliable channel where every event must land exactly once. Itâs not that big of a deal if one small mouse delta doesnât go through, but it definitely is a big deal if a click doesnât go through. 10. Browser compatibility detections Not every browser can do WebCodecs, secure contexts, or the input paths above. Rather than fail silently, I added a compatibility check on both the browser and client up front. It shows compatibility modals with per-feature lists to ensure the user knows whatâs going on. 11. Some more small fixes I added two quality-of-life additions: avatars (upload custom profile pictures) and zoom controls (ctrl/cmd +/-). 12. Encoders that donât explode when funny stuff happens Oh my godâŚone of the biggest issues by far. When I ran the NVIDIA encoder at high FPS, it didnât crash. However, the Intel Quick Sync encoder would arbitrarily crash at high FPS and wouldnât give a reason why. I audited a buncha different parts of my code and eventually found that FPS was the issue, not resolution or low-latency flags. Hence, I added a binary search that probes the hardware for its true maximum supported fps and clamps to it before the encoder can choke. Essentially, I ask the encoder âcan you do 1920x1080 at 240 fps?â â> ânoâ â> âwhat about 120 fps?â â> âyesâ â> âwhat about 180 fps?â. This keeps repeating till the max FPS is found and streamed to the client. Rounding out the release, I made a variety of different UI fixes like the modal fixes , backdrop overlap, a stray uninstall-modal backdrop, and cloud reconfig errors . More progress to come!
Sooooo this devlog is mostly comprised of website changes. I have a conference in San Francisco and wanted to polish up the app before publishing. Here are the main changes I made: 13. Random chores and updating the website I absolutely love shadcn-ui, but so do AI models. In past reviews by stardance raters, as well as family and friends, they pointed out the website looked AI-generated. Hence, I decreased the number of gradients and added basic animations to make the site feel more alive. This was a first for me to implement animations, but the Tailwind docs made it quite simple. I used a specific code-like font instead of the generic fonts I had and tidied up CSS classes. The biggest change was adding a blurred-geometric background for a nicer feel. 14. Redesigning the website completely I felt it was better to update the website as a whole, so I changed up the user interface. When I tested the app with real users, they complained that they didnât know how to actually use the app. I changed the hero design to have clearer text and added an SVG-animation component showing how the site actually works. The feature section stayed the same, but there was a highlights grid (inspo https://cider.sh/ ) to highlight the main features. The FAQ was shortened to my liking, and I pulled some utilities from Tailwind for animations. In terms of images, I updated the images of the app featured on the website and cleaned up some of the dimensions related to that CSS. The old homepage still lives inside OldHome() but isnât used anymore. 15. Tidying up the README and build workflows I edited the README to remove redundant information and make it more developer-focused. I also updated some information regarding GPU builds. For the build workflow, I ensured it would only run if the commit ended in ârebuildâ. This ensures unnecessary build minutes are not spent on small changes not requiring a full rebuild. 16. Wake lock API fallback This app aims to support all devices, but older devices haveâŚfunny APIs to say the least. For WebRTC, I implemented the legacy encoded streams API. However, the device would still turn off for seemingly no reason while the video was playing. On older devices, the wake lock API is not supported. However, thereâs a unique workaround for this: any video element playing on the webpage will keep the screen from dimming. Hence, I used the NoSleep library to create an off-screen 1-second video element that keeps looping, ensuring the display doesnât go dark. Some very fun stuff with browsers. Thatâs it for this devlog! Mostly minor changes, but the next one will have better SW encoding support among other changes. Stay tunedâŚ
I had so much fun at the conference in San Francisco! I met a lot of cool people who gave me advice on the app, although I didnât see the downloads spike đ. I primarily began working on a SW encoder and other miscellaneous changes: 17. Remote control toggle Sometimes, the user doesnât want a client to have remote control access. Although the purpose of the app is to have remote control, it is useful to disable this feature. On the frontend, I added a toggle switch that enables or disables the remote control backend. I was debating whether WebRTC negotiation was required as well, but decided to do so in the end. The remote control used data channels, so an unused data channel would result in slightly lower latency. Renegotiation ensured the stream stayed as efficient as possible without sending redundant data. 18. Update checking In order for current users to access newer versions, I wanted to add an update functionality. Iâm not using Tauriâs update plugin just yet, so I run a simple check. The app, on startup, checks the latest release tag on GitHub. If itâs not equal to the current version (rollback or higher version), the user is prompted to download the newer version. Automatic updates will come next. 19. The big boy: software encoding This oneâs been a long time coming. A lot of machines like VMs or computers with a weird setup just donât have a working hardware encoder (Intel/AMD/Nvidia), and until now that meant the app straight up didnât work there. So I built a full CPU-only x264 fallback. For the pipeline, the frames come as raw BGRA bytes that the other supporters already encoded. They must be converted to I420 before going to libx264, whose build I pulled from OBS. As a side note, the DLL is bundled with the app at runtime to ensure no missing dependencies. As with any encoder, the rate control is ABR with a tight VBV, as well as an infinite GOP. Besides the technical jargon, this just means latency is the north star and nothing else matters. The whole software variant is added to the encoder vendor enum, and wired into the fallback chain: if NVENC fails, try Intel; if Intel fails, fall back to software before giving up entirely. Thereâs also a manual override if someone really prefers software encoding, but this is not the default. Thereâs a big CPU cost compared to hardware encoding, so itâs very much a last resort and only kicks in if absolutely no GPU encoders are available. But âlast resort that worksâ beats âdoesnât work at all.â Thatâs it for this week! I plan to have some smaller quality-of-life changes and better updates coming soonâŚ
Oh my lordâŚI crammed a lot of features into this week. I have yet to do proper audits of the codebase as a whole, specifically related to latency optimizations. I added a lot more code that affects the WebRTC pipeline, but I at least got the core features working. 20. Automatic updates For a while, the app relied on manual updating. It would check the latest version on Github, but users would have to go to the website, download the installer, uninstall the current version, and reinstall the newer version. This also messed up config and was a huge pain. Hence, I generated my own signing keys and used the Tauri updater plugin to automatically update apps. When the app is first launched and if an update is available, it automatically downloads and installs it without any user action. To make this more robust, I added a progress bar while downloading the update. On Windows specifically, the app must be shut down and restarted, so a blocking modal prevents devices from joining till this is done. I originally made this modal manually, but switched to using AlertDialog from ShadCN. Another issue I faced was the latest.json manifest. As I used custom filenames when downloading and installing updates, I had to manually patch the JSON. I learned a lot about the Tauri updater Github action through this, as I had to figure out how Tauri generated build filenames and how I could safely update them. 21. Quality of life for client devices I finished QOL fixes on the client side: Remember past devices to quickly import preferences or ban devices (all config saving is IP-based) Warn if the user is attempting to connect from the same device (this app is a remote control tool, but you canât exactly remote control yourself) If the screen orientation changes, the virtual display is updated accordingly using CSS media queries to ensure a seamless experience A no fullscreen mode was added so users could quickly switch apps and maintain productivity 22. Quality of life for host devices I converted all in-app modals and error messages to JSON. This allowed me to add i18n language support, so I could easily translate my app to other languages. To detect and ensure only a single instance of the app was running, I previously used a file lock. However, there was an issue with MSI builds falsely detecting a file lock and not opening. I switched to a basic TCP model for IPC so that multiple processes running can figure out which was there first and shut down the others. 23. More more more Mac features! Iâve always felt a bit sad for my Mac users. I donât have a Mac to test on, so I keep borrowing my dadâs Mac, which results in insanely slow development times. Nevertheless, I made some serious progress this week. The biggest thing was a simpler installation process. Many users would complain that they didnât remember if theyâre on Intel or Apple Silicon, so I now distribute a universal DMG. In terms of the app itself, I added a permissions check for screen recording and input injection. It would run a live test of screen capture or key input to see if the app actually had permissions; therefore, down the road it wouldnât cause issues. I initially tried to do a soft check without an actual test (i.e., read the settings app), but this didnât work. The only foolproof way was to call the API itself. The biggest feature by far was adding Mac input injection. Using accessibility APIs and a charmap similar to Windows, it would inject input onto the Mac screen. I could remotely log in from my Chromebook and get a lot of work done. I mirrored the structure and code on the Windows input injection pipeline, so no major difficulties here. Thatâs it for this week! Lotta stuff added, especially for the Mac users. I have a long list of features to continue building, specifically regarding easier Windows uninstall processes, onboarding, and an overall better UX. See you soon!
I speedran shipping a buncha featuresâŚin the span of a few days. I logged a copious amount of hours on Hackatime building random stuff. I tried some things with recording system audio and building a driverâŚthose didnât go the best, but Iâll cover that in the next devlog. Here are the main changes this week: 24. Even more quality of life changes Compared to last time, I wanted the user experience to improve even more. Specifically, for the Windows client, a custom display driver is required. On Macs, the functionality I need is built in, so none is required. However, uninstalling this display driver used to be a pain for users. Now, I bundled it as part of the uninstall script. I wasnât sure how to do this, but Tauri has many useful guides and issues opened regarding custom WiX/NSIS code. When the window isnât focused, join and leave notifications are toasted. This allows the user to stay informed even when the app isnât open. Basic feature but very useful. Iâd often get annoyed that I needed to keep re-entering the password to log in to a previously connected device. Hence, I added auto-join for devices based on their IP. This ensures that commonly connected devices can save time when reconnecting. 25. Onboarding screens The app is intuitive to useâŚor so I thought? Some of my beta testers were confused as to the various features and how to use the interface. Hence, I used NextStepjs to add onboarding components. This would dim the UI and only highlight the component being displayed, along with a message next to it. I liked the styles of NextStepjs a lot, so I chose it. There were some issues regarding window resize, so I made the onboarding exit and reopen to the last step when the window is resized. This way, the positioning of elements was forcefully recalculated. 26. Random security fixes My app had various vulnerabilities scattered throughout, so I ran a vulnerability Claude skill and patched some holes. The main issues fixed were: Checksums of bundled DLLs and resources are checked before being pushed to GitHub Actions Tauri CSP and allow list are actually enforced instead of being set to allow all TLS cert used for hosting the HTTPS domain has more secure file system permissions to reduce unwanted tampering of files Devices are trusted by a uniquely generated token, not by IP, to decrease the chance of impersonators 27. Command-line interface A majority of the time on this devlog was spent on the CLI. It wasnât that hard (from a technical perspective), mainly just translating a lot of the UI code into Tauri CLI commands and mapping them correctly in the generated JSON file. One of the harder things to figure out was setting up cross-thread AppState, when the app wasnât exactly runningâŚturned out I just had to move the initialization command to before the window is created, so it would run inside both CLI and GUI modes. To present the QR codes better. I used qr2term to display the QR codes. By default, all logging is hidden. This turns ScreenExtend into a clean CLI mimicking the GUI. Hoorah! Thatâs it for this devlog. Not much to conclude, but plenty more features coming. Stay tuned!
Oh my lord, I keep forgetting to write devlogs every 10 hours and am losing hours on each one. Nevertheless, I finally finished audio work! Plus some other things like running claude security agents on the code base and patching stupid vulnerabilities. Hereâs how the week went: 28. HiDPI and Mac Issues Whenever I use my Mac with ScreenExtend, the stream looks blurry due to Macs having HiDPI screens. I fixed this by adding basic HiDPI scaling on Windows. The UI has a DPR slider based on autodetected values. This DPR is multiplied by the screen resolution for a shaper display. One issue that arose with the new displays was the fact that the display would randomly not scale properly, so the task bar and apps would appear tiny. To mitigate this, I reapplied all display settings after resolution changes and a timeout. 29. AUDIO WORKS!!!! For the longest time, I tried getting audio to work. On Windows, the process was straightforward: a WASAPI loopback system audio capture session. I wanted to build my own custom driver to capture audio faster, but this would be too expensive to deploy. I read other Rust implementations and quickly wrote the code. On the other hand, Mac was a whole different issue. On older versions of Mac, system audio recording is not supported. Hence, for Macs below 13.0, I wrote a custom audio driver. I didnât have a clue about implementing an AudioServerPlugIn on Mac, but worked out the specifics by looking at the Blackhole audio driver. I did have to proxy physical volume buttons to work (i.e. I listen for taps and change the audio level within the driver). For older Macs, I used ScreenCaptureKit with an extra audio flag. This was a simple fix to capture audio. On even newer Macs, thereâs a Process Tap API to record system audio with low latency. Once again, I didnât have much difficulties implementing these due to the abundance of documentation. 30. Streaming Audio over WebRTC (with A/V sync) When sending video and audio separately, the two are prone to fall out of sync, so watching movies or videos is difficult. To mitigate these issues, I wrote an A/V sync host clock. This packages the time on the host clock to audio samples and video frames, such that they can be reconstructed and coupled on the receiving end. On the browser side, I began by implementing a basic audio streamer with an audio element. However, similar to video, thereâs always a faster method possible. I used the AudioDecoder class from WebCodecs to implement a worklet class and jitterbuffer. In simple terms, this would decode audio on a separate thread, like WebCodecs prefers, and send the audio back to be played to the user. 31. Windows Video Encoding Speedups I made a few encoding speedups on Windows targets: The NVENC capture encode system uses a texture ring implementation: a pool of 3-5 encoder instances paired with a frame queue, allowing multiple frames to be encoded concurrently BGRA encoding is done directly in the library instead of using a third-party implementation Unchanged frames in DXGI capture are not encoded again, reducing CPU load 32. Mac Video Encoding Speedups I made a few encoding speedups on Mac targets: Request LatencyCritical activity for the session to ensure App Nap and other sleep measures donât affect the thread Analogous to DXGI, skip encoding when CGDisplayStream reports no dirty rects Not an encoding speedup, but preferring 5 GHz for Mac hosted networks to ensure higher speeds Lotta stuff done this week, am I right? I made lots of progress and finished the bulk of my features, although Linux support is still in the works. Iâll make the 1.0.0 release soon and start a Stardance ship as well. Iâll likely add Linux support after 1.0.0, as I need to research EVDI and the WSL display compositor, as well as other minor tweaks for Windows/Mac. See yâall in the next devlog!
One step closer to finally shippingâŚor so I hope. I speedran shipping this next feature, so it took a lot of time. This feature is mainly for myself. I have an old Mac (running 10.13 from 2017, really old I get itttt). I want my app to run on there, but it currently only supports 10.15+. Hence, I went down a funny rabbit hole in an attempt to add support. 33. Cleaning up dylib signature lookups at run time One of the key challenges I faced throughout development was how to have a unified codebase for multiple API versions. I decided that instead of version-gating APIs and guessing which beta/normal versions they would be accessible on, Iâd test for APIs at run time. I changed VideoToolbox to use this logic: it would attempt to set/use APIs and variables available at higher runtimes, but would work fine without them and have fallbacks. This ensured both legacy and modern systems functioned well. 34. Airplay automationsâŚ? As I was doing competitor research, I noticed many of the other apps supported Mac 10.13-10.15 as well as 10.15+, while mainly only supported 10.15+. Essentially, they started a fake Airplay server, had the Mac connect it, and set the display mode to âUse as separate displayâ. This would create a virtual display that the app would then use for its own functions. As ScreenExtend requires its own display on older machines, similar to this, where CGVirtualDisplay isnât an option, I decided to use this method. I had my app automate opening the Airplay menu and connecting as well, in addition to running the fake server. Most of the process was straightforward, especially due to the abundance of fake Airplay server implementations online and my own experience with apps like LonelyScreen. The one issue of this approach is that only one display can be connected at a time, so any tertiary devices wanting to connect have to wait their turn. I guess the only option is to by a new mac then⌠35. Client UI update cleanliness fixes Due to the one device restriction, I implemented a separate page that would be served if the display slot was being used up. It would be coupled with a short message explaining the consequences of the older Mac version. There were also bugs related to session teardown (keyboard still being locked, video stream still active in the background, etc) that I quickly squashed after finding them. Soooo in hindsight, I prolly shouldâve bumped this up to 0.6.0, but I left it at 0.5.4. Oh well, Iâll increment the version by next release. Only a few more features to go on the feature list before hitting v1 and shipping!!!
Ships:
Initial release for ScreenExtend! Please give feedback and read the initial devlog (shorter one here, longer one at https://github.com/ScreenExtend/ScreenExtend/blob/main/DEVLOG.md ) for detailed information.
Initial second release for ScreenExtend! Please give feedback and read the devlogs; theyâre detailed and describe the project a lot better than here. The website https://screenextend.app/ quickly summarizes it....
|
1793958758.2040858
|
1794045158.2040858
|
|
20498
|
Frictionless by @ilayabharathi | Stardance
|
ilayabharathi
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Frictionless by @ilayabharathi | Stardance
|
1794113257.7893937
|
1794718057.7893937
|
|
20499
|
ArduinoMarsAirlockSystem by @bobjoe | Stardance
|
bobjoe
|
1
|
1.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-18T18:13:43Z", "hours": 1.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made an Airlock system that opens the door, slowly closes the door, and locks the door. Originally I had a few problems with the project. I actually wanted to give it two more sensors, an Ultrasonic sensor and DHT11 sensor. Unfortunately the DHT11 sensor wasnât working and the Ultrasonic Sensor was broken. I decided to add LEDs to distinguish all 3 systems. Then I realized my LCD1602 wasnât working, so I tried rewriting that portion of code but it still didnât work. I downloaded some installations on Arduino IDE and it still didnât work. Then I realized I needed a potentiometer, and when I added it, it worked. I also ran into a problem with my servo motor not being calibrated to the same amount of degrees each time, I fixed it by rewriting the code to calibrate it to 0 degrees everytime the code runs. Now that Iâve ran into these problems, hopefully it will be easier to make hardware next time.", "repo": "https://github.com/bobjoe2009/ArduinoMarsAirlock", "demo": ""}]...
|
[{"post_id": 11411, "ts": "202 [{"post_id": 11411, "ts": "2026-06-18T17:53:33Z", "hours": 0.6833, "text": "I am working on a small Arduino system involving servo motors an LCD1602 and LEDs. This project mimcs airlock systems used in space shuttles. Right now the project has three different systems, Safe, Caution, and Airlock. Things that Iâm thinking about adding to this project : DHT11 (to analyze temperature and airlock during dangerous temperatures), Ultrasonic (Detecting any threats), IR sensor module (useful for detection too)."}]...
|
Title: ArduinoMarsAirlockSystem by @bobjoe | Stard Title: ArduinoMarsAirlockSystem by @bobjoe | Stardance
Devlogs:
I am working on a small Arduino system involving servo motors an LCD1602 and LEDs. This project mimcs airlock systems used in space shuttles. Right now the project has three different systems, Safe, Caution, and Airlock. Things that Iâm thinking about adding to this project : DHT11 (to analyze temperature and airlock during dangerous temperatures), Ultrasonic (Detecting any threats), IR sensor module (useful for detection too).
Ships:
I made an Airlock system that opens the door, slowly closes the door, and locks the door. Originally I had a few problems with the project. I actually wanted to give it two more sensors, an Ultrasonic sensor and DHT11 sensor. Unfortunately the DHT11 sensor wasnât working and the Ultrasonic Sensor was broken. I decided to add LEDs to distinguish all 3 systems. Then I realized my LCD1602 wasnât working, so I tried rewriting that portion of code but it still didnât work. I downloaded some installations on Arduino IDE and it still didnât work. Then I realized I needed a potentiometer, and when I added it, it worked. I also ran into a problem with my servo motor not being calibrated to the same amount of degrees each time, I fixed it by rewriting the code to calibrate it to 0 degrees everytime the code runs. Now that Iâve ran into these problems, hopefully it will be easier to make hardware next time....
|
1793919080.2022772
|
1794005480.2022772
|
|
20500
|
Job searching platform by @me_anishkumaryadav | St Job searching platform by @me_anishkumaryadav | Stardance...
|
me_anishkumaryadav
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: Job searching platform by @me_anishkumaryad Title: Job searching platform by @me_anishkumaryadav | Stardance...
|
1793379293.8572626
|
1793984093.8572626
|