|
29890
|
raycast engine by @kan411 | Stardance
|
kan411
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: raycast engine by @kan411 | Stardance
|
1792932794.4612145
|
1793796794.4612145
|
|
10358
|
rawFilm by @not-willem | Stardance
|
not-willem
|
0
|
2.69
|
0
|
[]
|
[{"post_id": 5368, "ts": "2026 [{"post_id": 5368, "ts": "2026-06-09T03:33:52Z", "hours": 1.8556, "text": "rawFilm a program to restore old films to look like they’ve been taken by a modern day digital camera currently ive made a command line interface and worked a little bit on the actual video fixing. Ive made background flicker fixing and i would show some examples but the video im using as a test is really long and i cant be bothered to get a smaller video haha anyway im gonna add in some video jitter fixes and denoising to remove the film grain and then MAYBE colorizing as an option but i assume it would be slow also i forgot to add but i HAVE implemented a FFmpeg thing to convert the video to an image sequence and then use pillow to edit it."}, {"post_id": 4059, "ts": "2026-06-07T07:32:06Z", "hours": 0.8306, "text": "Started coding a command line interface. Gotta actually make the program do its job but heres the plan: use Pillow to take the images, find the general brightness of the image and then tone up or down the rest of the images to have the same levels of brightness as the middle frame or a different frame if you choose then maybe a bit later I’ll add some line detection if its a cartoon to extract the lines and colors if a video is like REALLY bad but yeah :D it’ll be cool"}]...
|
Title: rawFilm by @not-willem | Stardance
Devlogs Title: rawFilm by @not-willem | Stardance
Devlogs:
Started coding a command line interface. Gotta actually make the program do its job but heres the plan: use Pillow to take the images, find the general brightness of the image and then tone up or down the rest of the images to have the same levels of brightness as the middle frame or a different frame if you choose then maybe a bit later I’ll add some line detection if its a cartoon to extract the lines and colors if a video is like REALLY bad but yeah :D it’ll be cool
rawFilm a program to restore old films to look like they’ve been taken by a modern day digital camera currently ive made a command line interface and worked a little bit on the actual video fixing. Ive made background flicker fixing and i would show some examples but the video im using as a test is really long and i cant be bothered to get a smaller video haha anyway im gonna add in some video jitter fixes and denoising to remove the film grain and then MAYBE colorizing as an option but i assume it would be slow also i forgot to add but i HAVE implemented a FFmpeg thing to convert the video to an image sequence and then use pillow to edit it....
|
1792572596.0107558
|
1793177396.0107558
|
|
29793
|
raven by @kuruni | Stardance
|
kuruni
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: raven by @kuruni | Stardance
|
1793170422.4606702
|
1793775222.4606702
|
|
7168
|
rat by @ttyChud | Stardance
|
ttyChud
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: rat by @ttyChud | Stardance
|
1792925610.2864182
|
1793789610.2864182
|
|
1983
|
rasterminal by @PavolUlicny | Stardance
|
PavolUlicny
|
1
|
470.39
|
8580
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-08T16:24:17Z", "hours": 449.0, "multiplier": 19.99, "payout": 8580, "blessing": "neutral", "text": "rasterminal rasterminal is a 3D model viewer in the terminal Why i decided to build it The original idea didn’t really have any big inspiration, I’ve just always been fascinated by the inner workings of 3D and how that all works. I’ve been wanting to build a project involving 3D for a while and I didn’t want to make just another program that uses libraries and GPU drivers to do all the work. So I came up with the idea: a software rasterizer that renders in the terminal! There are lots of TUIs and lots of boring old software rasterizer projects, so I just combined the two into something unique. And over time, I realized I could make it an actually useful tool, with no real competition: a 3D model viewer in the terminal. Sure, there are some similar projects on GitHub (like taigrr’s trophy), but none are actually usable with heavier models or support pixel graphics. What I learned I learned a lot. I really mean a lot. Anything from math and rendering to how terminals work and how to control them using escape sequences. I don’t want to sit here and name everything I learned over the period of the last 5 months, but I can confidently say that this project really taught me how much work goes into everyday software and how to actually develop and maintain a project professionally. The future of rasterminal The whole project is very far from done. You can see that from the latest release version: v0.1.0-alpha.2. I’ve got a lot of work to do and I’ve roughly got the major landmarks mapped out. Main things I definitely want to change/add at some point before v1 are: Add animation support (currently can only render still meshes) Complete the renderer (complete support for basically every feature of every format that makes sense to support) Add optional GPU acceleration (after I’m satisfied with everything else) Hardware / OS support Supports every major OS (Windows, Linux, MacOS, and any other POSIX-based OS, so practically everything), and every CPU that I could think of (any architecture, 32 or 64bit). You would have to actually try a to find a platform that it doesn’t support (most of the unsupported hardware are big-endian systems, which are basically phased out completely). This is one of the main goals of the project, so (almost) any modern machine with a terminal can run it. Special thanks Special thanks to anyone who followed, liked, helped, or otherwise supported the project in any way. I wouldn’t have had the motivation to push it this far if it wasn’t for you guys.", "repo": "https://github.com/PavolUlicny/rasterminal", "demo": "https://github.com/PavolUlicny/rasterminal/releases/tag/v0.1.0-alpha.2"}]...
|
[{"post_id": 70278, "ts": "202 [{"post_id": 70278, "ts": "2026-09-18T21:10:51Z", "hours": 6.11, "text": "Code quality and CI improvements Finally did the long overdue main loop refactor. The main loop is now way shorter, more readable and more testable. I just split off some of the main loop’s work into it’s own modules, which made them way better looking and also, since they are now standalone modules, actually testable. A big win for repo structure. In the process, I also replaced the input handling’s long if chain that made each character do it’s job with a switch statement. It’s more readable and theoretically faster, although since I compile it with -O3, it probably made no difference or an unnoticeable one at best. I also finally fixed the super long CI times. Until now, CI used to take ~50 minutes (depending on how fast the GitHub runner was) because of cppcheck. Everything else finished in under 10 minutes, but cppcheck stalled it for an hour. It was stalling in mesh_assimp.cpp (the assimp wrapper) for most of it’s runtime. I always thought it was because assimp is a very large library. So I experimented with it a little. I included everything I include in the wrapper into a test file with a little code and ran cppcheck on that. It finished in less than 10 seconds. Eventually, I found out it was somehow taking that long because the main loader function was too long and handled too much by itself. So i just refactored it into 3 separate functions, without changing the behavior at all. Somehow, I still don’t get why, it reduced the whole cppcheck run to 9 minutes. a more than 5x improvement, just because I split a function into more functions. I’m not complaining, but it’s definitely weird. CI is now way faster and adding new things is gonna be way smoother now."}, {"post_id": 68728, "ts": "2026-09-15T17:06:41Z", "hours": 6.6975, "text": "Miscellaneous fixes and improvements Fixed two races in platform code (one MacOS, one Windows) Removed build flags that disabled some compiler security hardening at the cost of a little performance Fixed the test framework to not freak out on NaN in near assertions Improved thread launching and handling in loaders and renderer So overall just boring fixes and improvements, nothing special."}, {"post_id": 66825, "ts": "2026-09-12T18:42:57Z", "hours": 8.5847, "text": "Refactored the platform layer The whole platform layer was just one file until now. Since I did a lot of work on it recently, it grew to over 2400 lines of code. It was super confusing and disorienting. So I decided to refactor it (split it) into 8 files, based on what they handle: console.h - saving/restoring terminal state control.h - termination signal handling file.h - file operations (64bit) input_reader.h - handling input (not parsing, that is it’s own file) shared_memory.h - shared memory handling for the kitty protocol terminal_io.h - writes output to the terminal terminal_query.h - querying the terminal for things like graphics capability, etc. timing.h - frame timing and sleeps"}, {"post_id": 64252, "ts": "2026-09-08T14:55:07Z", "hours": 2.3467, "text": "Last pre-release checks and cleanup I’m finally ready to release v0.1.0-alpha.2. Only notable thing I changed here is that I changed the default thread count: It now defaults to hardware concurrency everywhere. Other than that, I of course did final documentation checks and fixes and now I’m just waiting for CI to pass so I can tag it and let the release workflow do the last step. So this is hopefully the last devlog before my ship!"}, {"post_id": 63837, "ts": "2026-09-07T20:19:19Z", "hours": 10.4164, "text": "Did some polish and cleanup of the platform layer Did final polish and cleanup of the platform layer since I want to actually finally cut a release relatively soon and I just did a lot of work there. Fixed things like useless tests, outdated or wrong comments and some platform specific quirks. Probably actually gonna cut a release soon (this time for real). Also added early rejections for BVH and CSM files, since they contain no model geometry (they can’t currently be displayed at all) and documented the change. The code is basically done (hopefully, I really don’t want to find another big gap that’s gonna take a week to close), I just want to correct anything wrong in the README, changelog, manpage or help menu and maybe make them look a little better before cutting a release and shipping."}, {"post_id": 62122, "ts": "2026-09-05T11:43:50Z", "hours": 9.5678, "text": "Working on SIGSTOP and SIGCONT handling SIGSTOP and SIGCONT are POSIX signals for stopping and resuming a running process. I’m working on adding handling for these, so you can safely pause and unpause rasterminal at any time. This is a lot of work, since until now, we just set up the terminal on program start and cleaned up when the program exited. There’s a lot of quirks and weird scenarios that I have to handle, for example if another signal gets sent while cleaning up the terminal for SIGSTOP. I’m trying to catch as many edge cases by just doing random things while using the program and also with the help of AI to come up with potentially uncaught scenarios."}, {"post_id": 59763, "ts": "2026-09-01T18:10:34Z", "hours": 4.3639, "text": "Added handling for SIGINT, SIGTERM, SIGQUIT and SIGHUP I don’t really have much to say here, I just added the full per-spec handling for all these. Only remaining POSIX-only gap is now SIGSTOP/SIGCONT (stop/resume process). I’m also starting school now, so I’ll be working on this less."}, {"post_id": 58964, "ts": "2026-08-31T15:12:04Z", "hours": 3.8394, "text": "Fully fixed and merged the first POSIX cleanup item Well, would you look at that! That took significantly less time than the Windows fix. It is partly because it was a smaller fix and only part whole POSIX fix, while the Windows one was the whole thing and also the foundation had already been laid out from the Windows work and I just integrated the POSIX path into that, but it is also very much because Microsoft is a horrible, terrible company that can’t make good software. I mean, look at GitHub, they have been going downhill ever since they got acquired by Microsoft. Now that I got that out of my system, here’s what was fixed: If the program cannot enable raw mode at startup, it safely fails instead of continuing and corrupting the terminal state If the cleanup gets interrupted, it retries cleanup so it doesn’t leave the terminal state corrupted after one failed attempt Onto the next POSIX fix: handling SIGQUIT and SIGHUP."}, {"post_id": 58269, "ts": "2026-08-30T17:14:59Z", "hours": 8.6936, "text": "Merged the full Windows console restoration branch My nightmare is over. I hopefully won’t have to deal with Windows for a while now. Summary of what is now fixed/handled on Windows: Ctrl+C, Ctrl+Break and Q exits fully recover the terminal’s state Ctrl+C and Ctrl+Break don’t leak mouse escape sequences into the next prompt if you terminate while actively dragging a model A bunch of other minor Windows or cmd.exe specific quirks Only thing that isn’t handled (didn’t find a good way to handle it) is task manager “end process”. It kills the program without cleaning up and sometimes freezes the shell."}, {"post_id": 56881, "ts": "2026-08-28T21:26:16Z", "hours": 9.6883, "text": "I HATE WINDOWS Windows just doesn’t work. It doesn’t work. Nothing works on Windows. Everything breaks. I don’t get it. THE UNIT TESTS PASS ON WINDOWS CI BUT WHEN I ACTUALLY RUN THE TESTS ON WINDOWS IT FAILS????? HOW IS THAT EVEN POSSIBLE. The release is now definitely getting delayed by at least a week because I keep running into more and more and more and more and more and more and more and more and more issues. I hate Windows. Microslop is the only company that could mess up a basic terminal emulator. And I also have to reboot my PC every time I fix something and push it and then reboot to get back to linux. this is torture. At one point I tried to do it on a Windows VM on linux but that was too slow so I just gave up."}, {"post_id": 55585, "ts": "2026-08-27T15:06:53Z", "hours": 8.8714, "text": "Found a bunch of terminal cleanup gaps Most of them are Windows or cmd.exe specific (nothing ever works on Windows), but some are present on POSIX too. The Windows specific ones are: cmd.exe for some unknown reason doesn’t turn off the raw input sequences, so arrow keys don’t work like they should, even though I explicitly turn it off (????????) (I hate Windows, they always have to do something unexplainable for no reason just so your code doesn’t work as it should) when you terminate the program with ctrl+c or ctrl+break while actively dragging the model around, it sometimes leaks mouse escape sequences into the next prompt bunch of other weird small stuff that nobody cares about And the few on POSIX are mostly ctrl+z suspend/resume behaviour not recovering the terminal and the same thing with ctrl+\\ (SIGQUIT). I’m still working on fixing these. Most of the windows ones are already fixed, but I haven’t even started with the linux/POSIX ones. I have postponed the planned release to when I fix these + any other issues I find."}, {"post_id": 54695, "ts": "2026-08-25T19:14:01Z", "hours": 10.7308, "text": "Cutting a release The repo is in a pretty complete and polished state, so I’ll cut a release here. This will also probably be the last release before I ship, so I’m making sure that nothing is broken and everything works on every platform. I’ve still got a lot of work to do though, even after the end of stardance, like animations, glTF PBR, format completeness for every format, GPU acceleration, etc."}, {"post_id": 53861, "ts": "2026-08-24T15:48:08Z", "hours": 10.9639, "text": "Merged the full assimp integration into main I really don’t have much to say here, I’ve already put all the info about the branch into the past devlogs. All the formats work and the wrapper is very sturdy. I’ve found more bugs in assimp itself than my code (devlog on that soon). So, rasterminal can now load basically any 3D model you throw at it. Some of the formats assimp supports are so niche, I’ve never even heard of them."}, {"post_id": 53278, "ts": "2026-08-23T18:46:58Z", "hours": 13.1411, "text": "Fuzzing my assimp wrapper I’m trying a bunch of hand-crafted models from all the formats that I can load and trying to find things that dont load or render properly. Also had AI write me a simple fuzzer in python and I’m just letting it run for a few hours. Also auditing the assimp loader paths against my wrapper to find any format specific behaviour that should be handled. I’ve already found a bunch of things and I’m still finding more. Assimp has a lot of weird quirks and issues that I keep running into. Honestly kinda regretting the decision to integrate it, but since I’m already so deep in, I’ll just keep going."}, {"post_id": 52574, "ts": "2026-08-22T19:13:37Z", "hours": 11.0969, "text": "Still working on the assimp intgration Currently trying various models from all the different model formats that assimp loads. So far found a segfault, some weird behavior and integration mistakes that I made. Also found a small bug in assimp itself, for which I’ve submitted the PR with the fix to their GitHub repo. For anyone interested, here’s the PR: https://github.com/assimp/assimp/pull/6799"}, {"post_id": 51884, "ts": "2026-08-21T19:41:32Z", "hours": 6.9825, "text": "Working on assimp integration Yop, I’m adding the Open Asset Import Library as a fallback for any model formats that aren’t natively supported with their own dedicated loader (only ones with dedicated loaders are glTF2, PLY, STL and OBJ). I’m still keeping the dedicated loaders, because they are more feature-complete, to-spec and wayyy faster (especially the glTF one). I added it because I feel like for a 3D model viewer, support for many formats, even niche and obscure ones, is pretty important, even though nobody might use them. This roughly doubled compile time and almost quadrupled binary size, which also made CI take way longer (of course). It somehow made the MacOS runners take 50 minutes to compile (from the previous 3 minutes), but I fixed that by bounding the number of processes CMake can spawn to the number of threads on the runner (previously was using -j which spawns as many as it wants and it was spawning about 230 of them). I’m still testing how it handles various model formats and trying to find any reachable segfaults."}, {"post_id": 51275, "ts": "2026-08-20T20:14:42Z", "hours": 6.7119, "text": "Cleanup and restructuring changes After I just merged three big feature branches (kitty and sixel graphics protocols and the high-res performance branch), I needed to do some overdue cleanup and refactoring. And so I did: Collapsed the super long changelog entries into way more readable and legible points Restructured the src directory into multiple subdirectories because it had like 50 files already Sadly completely removed the Make build system, so now you can only build with CMake (CMake is very much evil and even more evil but it’s the only one of the two that supports windows and I was tired of managing two build systems) Removed the –graphics-scale flag, so now everything renders at native resolution And some small docs and comment cleanup"}, {"post_id": 50683, "ts": "2026-08-20T00:07:13Z", "hours": 12.3297, "text": "Finally merging the performance branch It’s finally time to merge the performance branch. I basically redesigned the whole renderer and rasterizer around high resolution workloads, where it would still choose the old high-poly paths where they were faster. Even snuck in some SSE2 SIMD code (picture), although I will probably be switching to a dispatch SIMD library like Google’s Highway. Not entirely sure it will be Highway or even if I will do that yet, that depends on the code complexity and before/after benchmarks."}, {"post_id": 49184, "ts": "2026-08-17T20:28:00Z", "hours": 14.5689, "text": "Still optimizing… Spent the first ~7 hours trying to find microoptimizations and each one was either a wash or worse somehow. The compiler works in mysterious ways. At some point, I just gave up and let Claude have a go at the optimizing. Surprisingly it actually came up with a lot of interesting optimization techniques and solutions that I definitely couldn’t have come up with on my own. But it found so much, that the whole diff adds 5k lines of code. So now I’ll be cleaning up, testing, and maybe further optimizing that diff…"}, {"post_id": 48227, "ts": "2026-08-16T15:09:59Z", "hours": 3.5944, "text": "My reported bug in libtermkey has been fixed in the newest version Just got an email from one of the maintainers that the crash bug i reported a month ago was fixed in the new release. libtermkey is a terminal input parsing library that I considered using and found a crash bug in. The bug was already fixed in neovim’s fork of the library, so i just pointed the maintainers at that fix. For anybody interested, here’s the issue link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1142891"}, {"post_id": 48078, "ts": "2026-08-16T11:20:07Z", "hours": 11.47, "text": "Working on improving performance With the addition of the high-res protocols, the target resolutions quickly went from hundreds or thousands of pixels to millions. So I now desperately need to improve performance. So far it’s looking promising: A whole model covering the camera 6 moving at 4k went from about 8 fps to 20-30 fps. Not ideal yet, but I think we’re on the right track. Super dense meshes (more than 2 million polygons) improved 2-3x Meshes with transparent parts improved about 2x While these wins may seem really big (they kinda are), the jump in resolutions still means they are barely usable interactively. I do want to add gpu acceleration later (with the cpu path as a fallback), but until then I want to make it as fast as I possibly can."}, {"post_id": 47112, "ts": "2026-08-14T19:18:15Z", "hours": 9.0333, "text": "Fully merged sixel Fully merged the sixel protocol implementation. Works on all platforms everywhere that supports it. So now both high-res terminal protocols done. Moving onto other minor things and especially performance."}, {"post_id": 46486, "ts": "2026-08-13T18:38:49Z", "hours": 10.6753, "text": "Working on adding full Sixel support Working on adding support for the other mainstream terminal pixel protocol of the main two - Sixel. Already did fully implemented the kitty protocol last time, so once I’m done with this one, I’ll be done with terminal protocols (at least for the near future, hopefully). There are some other ones like the iterm2 protocol, but that one’s pretty rare and I won’t add it unless I really don’t have anything better to do. It’s basically done, just need to polish it and test it on a bunch of terminals and operating systems to make sure everything works before merging."}, {"post_id": 44676, "ts": "2026-08-10T16:23:20Z", "hours": 4.0767, "text": "Fully merged and done with Kitty Finally completed the kitty protocol implementation. It is kinda slow, since the resolution is so much bigger, so I will try to optimize the high-res performance even more. So now the next two big milestones are: Add Sixel on top of kitty, that’ll be a lot of work Optimize the rasterizer even more I was thinking of maybe adding gpu rendering as an option for super large meshes or high-res scenarios, but idk. I’ll definetly keep the pure cpu renderer for computers without gpus, but I’m not sure about a gpu implementation. It would be hard to do, less portable and it might not even work that well."}, {"post_id": 44513, "ts": "2026-08-10T09:59:08Z", "hours": 6.8483, "text": "Found a bug in Ghostty’s kitty protocol handling Ghostty is a modern and fast terminal emulator that i personally use. While testing the kitty protocol feature in rasterminal, I found a Ghostty bug that lagged my whole computer after a few minutes. I tested it in Kitty (terminal emulator) and there it worked fine. I looked at Ghostty’s code vs Kitty’s, found the bug and reported it to the Ghostty maintainers. Mitchell himself (the creator) fixed it in like 2 hours. Honestly I’m kinda sad I didn’t get to become a contributor and fix the bug, but since it was a small fix and I already described it in the issue, I get why Mitchell just fixed it in main. Here’s the full issue: https://github.com/ghostty-org/ghostty/discussions/13719"}, {"post_id": 43513, "ts": "2026-08-08T20:35:37Z", "hours": 7.6361, "text": "Working on adding support for the Kitty protocol Some modern terminals like Kitty and Ghostty have support for the Kitty protocol. It’s a feature that allows you to display high resolution content like images and videos in the terminal without it looking super pixelated. There’s also the Sixel protocol, which is basically the same thing but a little worse and more widely supported (even Windows terminal has it). I’ll add Sixel after i merge Kitty to main. It is very clearly a worthwhile feature and I have been planning to add it from the start of the project. Today I finally decided that it’s time. Most of the work is already done on the branch and i’m just polishing out the bugs and issues before I merge. In the photos, you can see the comparison between using just the block characters and using Kitty. It is a night and day difference. Although the performance isn’t great at that high of a resolution, but I’m still working on optimizing that."}, {"post_id": 42752, "ts": "2026-08-07T17:00:51Z", "hours": 3.5125, "text": "Minor comment cleanup Just did some comment cleanup: Deleted redundant comments and why comments Removed separator comments Compressed or rewrote some really long comments (without removing the info they give)"}, {"post_id": 42161, "ts": "2026-08-06T19:24:06Z", "hours": 8.2153, "text": "Added issue templates + contributing documentation Added templates and a config for submitting GitHub issues, for both bug reports and feature requests. Also added a CONTRIBUTING.md for clear instructions on how to make, structure and audit code contributions. (tests, linters, formatting, etc.) I tried to make some optimizations to the renderer by auditing the compiler generated assembly and looking for inefficiencies, but everything i tried turned out to actually hurt performance. And GitHub actions decided to have a major outage right when i pushed the commits, so that’s awesome"}, {"post_id": 39599, "ts": "2026-08-02T18:05:04Z", "hours": 7.4436, "text": "Completely redesigned and rewrote the HUD The HUD used to be just a single line at the bottom of the screen aligned to the left. It looked pretty bad, but it did tell the user everything they needed to know. [picture 1] First, I added model name sanitization, so models with control bytes like newline ( \\n ), line feed or other symbols like emojis can’t break the whole program when trying to display them in the HUD. Then, I completely redesigned the whole HUD to look better and be more robust, while still telling the user everything they need to know. I went with this design [picture 2]: On the left, you only have the model name. In the middle, first you have the current shading mode (highlighted in cyan), then the lighting mode in plain white and then the background color in gray. All three middle indicators are separated with a dot and are different colors, so nobody can confuse them. On the right, there’s 3 boolean indicators: spin (if the model spin is on), backface cull (if it’s currently culling backfaces) and texture (if it’s showing the texture, isn’t there at all on models without a texture). They are gray if inactive and cyan if active. The last thing on the right is just the fps number. There can also be optional indicators: Wireframe color (in the middle, after the shading mode) which only shows up in wireframe mode. [picture 3] First person speed multiplier (on the right, between the bools and the fps number) which shows up only in first person mode. [picture 4] I also made each “island” cleanly disappear when the terminal’s width is too low instead of just slowly getting cut off letter by letter. I think this design looks better, less cluttered and is pretty easy to understand at a glance. I would very much appreciate a star on GitHub!"}, {"post_id": 38478, "ts": "2026-07-31T21:36:35Z", "hours": 7.7572, "text": "Did a smaller fix and added a pretty big feature First, let’s talk about the small fix: I Fixed a super long model name showing up in the HUD in it’s full length, often blocking out other HUD elements. Previously, the HUD would display a model name of any length. Now there’s a hard cap of 24 chars, with any name longer than that truncated (middle style truncation) to fit into that limit. And now the big feature: Added a first person noclip-style camera mode. It’s accessed with the –first-person flag and let’s you explore the model as a floating camera (not bound like the default orbit camera). It was honestly easier to implement than I thought it would be. With it, I added two new keybinds special to the first person mode - E and V for going up and down. They don’t do nothing in orbit mode. Also added a second –first-person-speed flag for controlling the initial movement speed. It is also controllable during runtime with scrolling or +/- (I didn’t know what to bind these to in this mode since you can’t zoom like in orbit mode and this was the only place where they fit). In the photos, you can see some angles taken in the first person mode that weren’t possible in the default orbit mode."}, {"post_id": 37806, "ts": "2026-07-30T19:08:29Z", "hours": 2.7436, "text": "Finally committed and pushed the input rework Tested it on both linux and windows and everything seems to work. No inputs interpreted as other inputs, all edge cases handled, just works. Finally can move onto other things."}, {"post_id": 37656, "ts": "2026-07-30T15:25:21Z", "hours": 9.285, "text": "Still working on the input parsing system It is very hard and I keep finding bugs and reasons to redesign it. I’m in pain. I do think I’m getting closer to the final robust design."}, {"post_id": 36697, "ts": "2026-07-28T22:28:53Z", "hours": 9.9361, "text": "Working on completely rewriting the current input parsing handling The current input handling is subpar at best; it interprets a lot of random keys as escape, which currently quits the program (This will also be changed to Q and Ctrl+C only. Kind of a no-brainer since this is the more standard choice for TUIs - for example btop - and it also means I don’t have to deal with the headache of distinguishing function keys and others from escape) and has a lot of other quirky behavior that needs fixing. I’ll also try to improve robustness against malformed input like a leaky SSH session. There are a lot of various edge cases and situations where you have no way to distinguish real input from malformed input. This is all a very major pain in the ass. And I thought figuring out the raw mode output would be the hard part. And after all this, I’ll end up with way less attention than strictly slower, less robust competitors, just because they already have an audience from other projects. I bet nobody will even read this. I’m basically talking to myself right now. Or maybe, just to spite me, the algorithm will push this more than my other devlogs."}, {"post_id": 35924, "ts": "2026-07-27T17:55:43Z", "hours": 8.7953, "text": "So, i found two memory bugs in a widely used terminal input library I was researching terminal input libraries to use for this project because my current approach was so buggy that it wasn’t worth fixing. Both of them are memory bugs in the libtermkey library. There are forks of the lib with this fixed, but since many projects still rely on this lib, i submitted them anyways. I’ve also confirmed that the bug is present on my machine on Ubuntu 24.04 LTS on Neovim, because it links the vulnerable shared library. I didn’t mark them as CVEs (hopefully that isn’t a problem). If anyone want’s to look at the bug reports, they are at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1142891 and https://bugs.launchpad.net/ubuntu/+source/libtermkey/+bug/2161916"}, {"post_id": 33607, "ts": "2026-07-23T17:38:48Z", "hours": 4.5575, "text": "Added more CLI flags for startup customizability Added flags to set the camera pitch, yaw and zoom on startup. Now every runtime-settable variable can be set during startup through the CLI. The R button now resets the state to the CLI set state, not to factory defaults."}, {"post_id": 32607, "ts": "2026-07-21T21:48:11Z", "hours": 4.4442, "text": "Added –spin-speed and –spin-direction flags Added CLI flags for the spin speed and direction. The speed is in deg/s and the directions is simply left or right. Here’s what 1000 deg/s looks like spinning to the right:"}, {"post_id": 30923, "ts": "2026-07-18T22:17:24Z", "hours": 8.6892, "text": "Did a bunch of small code quality and usability improvements Fixed a Windows bug that crashed the program on model sizes bigger than 2GB, improved the orbit usability (fixed mouse drag behavior when models are turned upside down), and did a few cleanups and fixes in the CLI parsing. I’m planning on adding a few CLI flags that I think can be very useful for some people, specifically better spin settings, starting camera angle/zoom control and a few more."}, {"post_id": 29772, "ts": "2026-07-16T21:27:23Z", "hours": 0.7175, "text": "Finally merged color-fallback, I can move onto other things The branch is finally merged. I’ve accumulated a bunch of usability and code quirks and issues that i can finally get to now that the branch is merged. So now I’ll be reworking all the CLI flags, camera and other components. And we also passed the 700 commit mark with this merge!"}, {"post_id": 29484, "ts": "2026-07-16T13:40:29Z", "hours": 4.9444, "text": "Changed the 24bit to 256 color palette conversion logic Until now, the conversion picked the closest color possible mathematically. But from testing on a bunch of different models, I’ve realized that it doesn’t actually look very close to the human eye. So I swapped it out for a different method, called CIELAB distance. Now it still doesn’t look perfect, but as a fallback for older terminals it’s close enough."}, {"post_id": 28408, "ts": "2026-07-14T17:26:16Z", "hours": 9.2258, "text": "Working on a –color compatibility flag The color terminal compatibility thing I was working on has landed in the branch, now I’m adding a –color flag to override the automatic capability detection for situations like ssh, where we almost always degrade to the 256 color pallete for maximum compatibility. So now you’re gonna be able to use the right color mode even if the automatic detection is wrong for your situation."}, {"post_id": 27302, "ts": "2026-07-12T19:23:17Z", "hours": 10.3522, "text": "Working on terminal color capability detection I am adding automatic terminal capability detection, meaning that rasterminal will get the terminal type and either refuse to render on super old or “dumb” terminals, degrade on some terminals and render normally on modern ones."}, {"post_id": 24314, "ts": "2026-07-07T20:18:01Z", "hours": 5.1908, "text": "Working on adding 256 color support Some older terminals can’t display full 24bit RGB colors and use a 256 color palette instead. I’m adding a fallback so the older terminals can still use rasterminal. It still calculates the full old RGB colors, but then just maps them to the nearest 256 color with LUTs. On a side note, I switched my terminal emulator from Kitty to Ghostty."}, {"post_id": 23070, "ts": "2026-07-05T20:10:12Z", "hours": 10.4403, "text": "Working on portability Did a bunch of small fixes and improvements in the last ~week. Right now I’m on vacation for the next couple of days, so I won’t be active. I am currently working on broader terminal and platform support, so older systems and terminals will be able to run cleanly with some fallbacks or will fail loud with a clear message about what isn’t supported."}, {"post_id": 19371, "ts": "2026-06-30T17:34:50Z", "hours": 5.1925, "text": "Completely removed the shadow map Before, rasterminal built a shadow map on model load and displayed it during runtime. I now completely removed it, because it was slower during load, slower during runtime, sometimes looked broken on curved surfaces and added essentially no value. Here, the first picture is with the shadow map and the second is without."}, {"post_id": 18685, "ts": "2026-06-29T21:27:29Z", "hours": 13.4722, "text": "Wasted 7 hours of my life Did a bunch of smaller cleanups and fixes, and then I tried to template the unlit and lit paths in the rasterize_flat function, which turned out to be a performance regression. Awesome."}, {"post_id": 17021, "ts": "2026-06-27T17:00:39Z", "hours": 5.7733, "text": "Added a release workflow, manpage and changelog I added a github release workflow that works alongside the changelog and released the first pre-release version: v0.1.0-alpha.1 Also added a manpage and an install target to make and cmake that installs the binary, docs and manpage into the path."}, {"post_id": 16313, "ts": "2026-06-26T15:28:43Z", "hours": 5.1883, "text": "Pararelized the wireframe shading mode I did a bunch of small things alongside it, but the main feature for this devlog is the pararelization of the wireframe shading mode. It was previously fully single threaded, but it wasn’t that hard to pararelize, i just had to make the function it used to write into the framebuffer (draw_line) CAS atomic, to avoid race conditions. Now wireframe is the fastest shading mode in basically all scenarios. Below, you can see a performance benchmark (built into rasterminal using a flag) with wireframe mode on a super dense mesh and how the wireframe mode looks like (you can also cycle the colors)."}, {"post_id": 15932, "ts": "2026-06-25T21:35:36Z", "hours": 1.9053, "text": "Split the tests into sub-directories The test suite is now very long (20k LOC across 47 files), so i decided to split it into sub-directories instead of just having 47 files in one flat dir. It’s cleaner, more maintainable and looks better."}, {"post_id": 15741, "ts": "2026-06-25T16:48:43Z", "hours": 4.9903, "text": "Completely removed gouraud shading mode Gouraud was previously the main shading mode, but now I’ve just completely removed it. It was by far the slowest, while not adding any actual value to the project. Blinn-phong lighting is faster AND it supports more features (normal maps, etc.), so there was just no point in keeping gouraud. Now that I’ve removed it, the project has less code to maintain and a faster default shading mode with more features."}, {"post_id": 15551, "ts": "2026-06-25T08:50:38Z", "hours": 3.7597, "text": "Added proper OBJ bump map support OBJ bump maps are textures for simulating bumps and wrinkles on models. Blender used to author bump maps as normal maps for some reason, so I made it automatically detect if it’s a normal map disguised as a bump map and handle it well, since there are a lot of old Blender OBJ models in the wild. But it also handles bump maps as bump maps normally, so it’s basically the best of both worlds."}, {"post_id": 15117, "ts": "2026-06-24T15:43:58Z", "hours": 6.87, "text": "Added texture transform into the TEXCOORD branch and merged it into main Not that hard, just read it, pass it to the rasterizer and then display it. I did have a very sneaky bug in the loader that made the whole feature render wrong, where I just had to negate one value to fully fix it, but now everything fully works. Below you can see the Khronos test asset for texture transforms. (tick means fully working, clearcoat is not yet implemented so it doesn’t show as working)"}, {"post_id": 13839, "ts": "2026-06-22T17:59:12Z", "hours": 5.2097, "text": "Added TEXCOORD_1 support glTF sometimes authors a second TEXCOORD set (first one is TEXCOORD_0, 0 indexed numbering). The official spec only requires support for the first two TEXCOORD sets, even though there can theoretically be any number of them in a model. That said, major model exporters don’t author any more than the two sets, so to avoid extra work, I only added support for 0 and 1. (not merged into main yet, I want to polish it a little and maybe add KHR_texture_transform support on top of it first)"}, {"post_id": 12798, "ts": "2026-06-20T22:37:18Z", "hours": 7.6314, "text": "Optimized the transparent cleanup path in the renderer After rendering the model in the transparent path, we have to resolve the transparent pixels, which basically just pastes in the pixels behind it and sometimes tints it based on how dark and what color the transparent material is (tinted glass will make the things behind it darker, normal glass will be mostly completely untinted). Before, the resolve function looped over every single pixel in the frame, even non-transparent and background ones. This is obviously wasteful. So I made it find the smallest box, in which all the transparent pixels of the whole frame fit and just looped over that. It recovered the overhead of the transparent resolve on models with smaller transparent parts, but it also made fully transparent or mostly transparent models slightly slower (it still basically loops over almost the whole screen on these types of models, so keeping track of the smallest bounding box while also still doing the same work as before made it a little slower). But the performance benefits for the average model outweighed the losses on rare fully transparent models. In the image, you can see the benchmark results versus the baseline."}, {"post_id": 12171, "ts": "2026-06-19T21:42:34Z", "hours": 6.6653, "text": "Made the shading mode branches compile time instead of runtime in the renderer with templates Did the same template if constexpr (compile time if branches) thing that we already do for opaque/transparent models with the shading mode (was a runtime per triangle if branch before), which improved performance. It basically just makes a new copy of the function for each shading mode x each transparency mode, so 4x2 which is 8 slightly different functions and uses the correct one on each call. That increases binary size and icache pressure, but drops per triangle or per pixel if branches that hurt performance, so it’s an overall performance win. Benchmarked across a ton of different resolutions, models, shading modes, etc. (the benchmark by itself took like 2 hours to run)"}, {"post_id": 10115, "ts": "2026-06-16T18:24:38Z", "hours": 4.0297, "text": "Added support for wrap modes for textures Only in glTF and OBJ models (the only ones that support it) and verified with the Khronos group sample assets model. Also added PLY texture support."}, {"post_id": 9453, "ts": "2026-06-15T20:20:25Z", "hours": 4.6839, "text": "Working on adding supersampling anti-aliasing Still a work in progress and I might not merge it into main, because it’s a lot of work for not that much benefit. I have to catch a lot of bad_allocs and things like that for super large SSAA sizes, which is really annoying and can affect performance. SSAA works by rendering at a higher resolution and then downscaling for better edges (makes edges smooth and fade-in instead of jagged) Picture with 2x SSAA and without SSAA:"}, {"post_id": 8652, "ts": "2026-06-14T11:36:32Z", "hours": 5.2058, "text": "Adapted the arg parsing and CLI behaviour to the GNU standard Now, rasterminal’s CLI behaves under the GNU CLI standards, so on par with most linux tools."}, {"post_id": 8162, "ts": "2026-06-13T16:37:29Z", "hours": 2.8394, "text": "Added deduplicating vertices to the stl loader. After two unsuccessful and unmerged branches, I finally did something useful on main. I used to deduplicate the vertices in stl_reader and then reduplicate them in the loader. But now, we just dedup in stl_reader and use those. That also allowed me to enable ambient occlusion, which was disabled for stl before. And now crease smoothing fully works too. And it’s faster (runtime wise, load time is slower because of ambient occlusion and crease smoothing that weren’t there before). So an all-round very positive change, and also an end to my non-merging dry spell."}, {"post_id": 7990, "ts": "2026-06-13T10:20:35Z", "hours": 2.4908, "text": "Replaced tinyobjloader with rapidobj for way faster obj parsing But after actually replacing it and integrating it into the source code, i realized it’s not worth it, because rapidobj just has too many downsides and isn’t very actively supported anymore. For example, it doesn’t support multiple mtl files, which is against the spec. So if i want to keep it spec compliant, I need to find a workaround for it, which just isn’t worth the speed increase of rapidobj, even if it’s like 4x faster (from my testing on a large obj) The graph is from this article: https://aras-p.info/blog/2022/05/14/comparing-obj-parse-libraries/"}, {"post_id": 7643, "ts": "2026-06-12T19:26:54Z", "hours": 8.7975, "text": "I tried to rewrite the STL loader from scratch for more performance But it’s taking super long and I’m way too bored with it, so I think I’ll just abandon the branch and work on something else."}, {"post_id": 6791, "ts": "2026-06-11T11:35:25Z", "hours": 3.6575, "text": "Added full native 32 bit support for all platforms Didn’t have to redesign any of the source code (thankfully), just some warning suppressing and fixing some static casts. Also added a CI job that’ll flag future 32 bit compatibility regressions."}, {"post_id": 5755, "ts": "2026-06-09T17:34:17Z", "hours": 4.1133, "text": "Transparency is fully done and merged. Did some polish, cleanup and optimization on the transparency branch and successfully merged into main."}, {"post_id": 4897, "ts": "2026-06-08T13:53:56Z", "hours": 3.2906, "text": "Transparency is basically done, with caveats. Transparency works correctly, but transmission , which is completely different, is simplified to transparency. So for spec-complete gltf, I would need to implement the whole transmission pipeline, which I’m way too lazy to do right now. So for now, we just simplify it to transparency and call it a day."}, {"post_id": 4320, "ts": "2026-06-07T16:09:10Z", "hours": 6.2586, "text": "Working on adding transparency support. For that, I have to completely rework the rendering loop and the rasterizers, so basically the whole core of the project. It’s going very badly. And since performance is a big factor here, I’m going for a template approach so the transparency overhead doesn’t affect non-transparent meshes."}, {"post_id": 3846, "ts": "2026-06-06T22:11:48Z", "hours": 3.5269, "text": "I did a hot-loop performance cleanup run, because the hot loops were getting slower with new features, and I found a big optimization opportunity in clip-near call sites: clip_near slices off the part of a triangle that pokes behind the camera’s near plane, but almost every triangle is fully in front of it with nothing to clip. The pipeline still called it for all of them, and in the compiled binary that common case just copied all three vertices to memory and back, millions of times a frame. The fix was to check inline whether the triangle is fully in front and skip the call entirely if so. Result on a 2.77M-triangle model: median frame time dropped from 21.1 ms to 19.2 ms, about 8.7% faster."}, {"post_id": 3572, "ts": "2026-06-06T15:51:49Z", "hours": 2.4386, "text": "Because of all the libraries I added, the binary size increased significantly. I don’t use most of the vendored code, so I added build flags to ignore unused code in the final binary. Other than that, I added some other performance flags and also a CMakePresets.txt. It took longer than it should’ve, because I tested and benchmarked a bunch of other configs and flags. I put off PGO for now."}, {"post_id": 2939, "ts": "2026-06-05T20:55:20Z", "hours": 3.9267, "text": "I wired in Webp image format support by vendoring in google’s libwebp decoding library. It wasn’t that hard to wire into the source code, the hard part was the vendoring, dealing with licenses and professional vendoring practices. Only thing that remains to add for full gltf extension support is avif image support, but I’ll do that later."}, {"post_id": 2739, "ts": "2026-06-05T14:38:57Z", "hours": 1.3417, "text": "I just added unlit material support, which means materials that are supposed to stay intentionally unaffected by lighting render correctly. Pretty straightforward change, just read it at load time and then check if that material is unlit during the lighting pass and skip it."}, {"post_id": 2631, "ts": "2026-06-05T08:21:00Z", "hours": 3.3225, "text": "Reworked the whole readme with better instructions, screenshots and a gif. The gif was super annoying to polish, because i used asciinema which records all the setup escape sequences so there were gaps at the start and end that i had to manually read and remove. And I also had to perfectly close it exactly when it did one full rotation and that took like an hour to perfect. At least now I don’t have to touch the readme for a while."}, {"post_id": 2311, "ts": "2026-06-04T18:46:14Z", "hours": 3.1892, "text": "Well, I tried to refactor the main rendering loop for like the third time, because it’s horrifyingly indented, but it has defeated me once again. At this point, I’m confident that it’s impossible to do without a noticeable drop in performance, or g++ is just ragebaiting me. I installed a rainbow indentation neovim plugin just to show the absurdity of this."}, {"post_id": 386, "ts": "2026-06-01T18:58:14Z", "hours": 0.6783, "text": "I just implemented KTX2 and Basis texture support, which are special compressed texture formats. So now any models with these textures are viewable in rasterminal."}, {"post_id": 359, "ts": "2026-06-01T17:59:06Z", "hours": 4.5428, "text": "Hey everyone, I want to introduce my project! rasterminal is a full software 3D rasterizer and model viewer that runs entirely in your terminal. The whole rendering pipeline is implemented from scratch. I only rely on third-party libraries for load-time things like 3D model parsing, image parsing, and decompression. It doesn’t touch the GPU at all, running purely on the CPU. That makes it completely safe for SSH usage, though it does come with a performance cost. I use multithreading to recover some of what’s lost, and the result is still significantly faster than any other terminal 3D viewer I’ve come across. Right now I’m focused on broader 3D format feature support and transparent material rendering. If you want to try it out, I’d love to hear what you think, feedback and issues are very welcome over on GitHub. https://github.com/PavolUlicny/rasterminal Thanks for any support! 🙏"}]...
|
Title: rasterminal by @PavolUlicny | Stardance
De Title: rasterminal by @PavolUlicny | Stardance
Devlogs:
Hey everyone, I want to introduce my project! rasterminal is a full software 3D rasterizer and model viewer that runs entirely in your terminal. The whole rendering pipeline is implemented from scratch. I only rely on third-party libraries for load-time things like 3D model parsing, image parsing, and decompression. It doesn’t touch the GPU at all, running purely on the CPU. That makes it completely safe for SSH usage, though it does come with a performance cost. I use multithreading to recover some of what’s lost, and the result is still significantly faster than any other terminal 3D viewer I’ve come across. Right now I’m focused on broader 3D format feature support and transparent material rendering. If you want to try it out, I’d love to hear what you think, feedback and issues are very welcome over on GitHub. https://github.com/PavolUlicny/rasterminal Thanks for any support! 🙏
I just implemented KTX2 and Basis texture support, which are special compressed texture formats. So now any models with these textures are viewable in rasterminal.
Well, I tried to refactor the main rendering loop for like the third time, because it’s horrifyingly indented, but it has defeated me once again. At this point, I’m confident that it’s impossible to do without a noticeable drop in performance, or g++ is just ragebaiting me. I installed a rainbow indentation neovim plugin just to show the absurdity of this.
Reworked the whole readme with better instructions, screenshots and a gif. The gif was super annoying to polish, because i used asciinema which records all the setup escape sequences so there were gaps at the start and end that i had to manually read and remove. And I also had to perfectly close it exactly when it did one full rotation and that took like an hour to perfect. At least now I don’t have to touch the readme for a while.
I just added unlit material support, which means materials that are supposed to stay intentionally unaffected by lighting render correctly. Pretty straightforward change, just read it at load time and then check if that material is unlit during the lighting pass and skip it.
I wired in Webp image format support by vendoring in google’s libwebp decoding library. It wasn’t that hard to wire into the source code, the hard part was the vendoring, dealing with licenses and professional vendoring practices. Only thing that remains to add for full gltf extension support is avif image support, but I’ll do that later.
Because of all the libraries I added, the binary size increased significantly. I don’t use most of the vendored code, so I added build flags to ignore unused code in the final binary. Other than that, I added some other performance flags and also a CMakePresets.txt. It took longer than it should’ve, because I tested and benchmarked a bunch of other configs and flags. I put off PGO for now.
I did a hot-loop performance cleanup run, because the hot loops were getting slower with new features, and I found a big optimization opportunity in clip-near call sites: clip_near slices off the part of a triangle that pokes behind the camera’s near plane, but almost every triangle is fully in front of it with nothing to clip. The pipeline still called it for all of them, and in the compiled binary that common case just copied all three vertices to memory and back, millions of times a frame. The fix was to check inline whether the triangle is fully in front and skip the call entirely if so. Result on a 2.77M-triangle model: median frame time dropped from 21.1 ms to 19.2 ms, about 8.7% faster.
Working on adding transparency support. For that, I have to completely rework the rendering loop and the rasterizers, so basically the whole core of the project. It’s going very badly. And since performance is a big factor here, I’m going for a template approach so the transparency overhead doesn’t affect non-transparent meshes.
Transparency is basically done, with caveats. Transparency works correctly, but transmission , which is completely different, is simplified to transparency. So for spec-complete gltf, I would need to implement the whole transmission pipeline, which I’m way too lazy to do right now. So for now, we just simplify it to transparency and call it a day.
Transparency is fully done and merged. Did some polish, cleanup and optimization on the transparency branch and successfully merged into main.
Added full native 32 bit support for all platforms Didn’t have to redesign any of the source code (thankfully), just some warning suppressing and fixing some static casts. Also added a CI job that’ll flag future 32 bit compatibility regressions.
I tried to rewrite the STL loader from scratch for more performance But it’s taking super long and I’m way too bored with it, so I think I’ll just abandon the branch and work on something else.
Replaced tinyobjloader with rapidobj for way faster obj parsing But after actually replacing it and integrating it into the source code, i realized it’s not worth it, because rapidobj just has too many downsides and isn’t very actively supported anymore. For example, it doesn’t support multiple mtl files, which is against the spec. So if i want to keep it spec compliant, I need to find a workaround for it, which just isn’t worth the speed increase of rapidobj, even if it’s like 4x faster (from my testing on a large obj) The graph is from this article: https://aras-p.info/blog/2022/05/14/comparing-obj-parse-libraries/
Added deduplicating vertices to the stl loader. After two unsuccessful and unmerged branches, I finally did something useful on main. I used to deduplicate the vertices in stl_reader and then reduplicate them in the loader. But now, we just dedup in stl_reader and use those. That also allowed me to enable ambient occlusion, which was disabled for stl before. And now crease smoothing fully works too. And it’s faster (runtime wise, load time is slower because of ambient occlusion and crease smoothing that weren’t there before). So an all-round very positive change, and also an end to my non-merging dry spell.
Adapted the arg parsing and CLI behaviour to the GNU standard Now, rasterminal’s CLI behaves under the GNU CLI standards, so on par with most linux tools.
Working on adding supersampling anti-aliasing Still a work in progress and I might not merge it into main, because it’s a lot of work for not that much benefit. I have to catch a lot of bad_allocs and things like that for super large SSAA sizes, which is really annoying and can affect performance. SSAA works by rendering at a higher resolution and then downscaling for better edges (makes edges smooth and fade-in instead of jagged) Picture with 2x SSAA and without SSAA:
Added support for wrap modes for textures Only in glTF and OBJ models (the only ones that support it) and verified with the Khronos group sample assets model. Also added PLY texture support.
Made the shading mode branches compile time instead of runtime in the renderer with templates Did the same template if constexpr (compile time if branches) thing that we already do for opaque/transparent models with the shading mode (was a runtime per triangle if branch before), which improved performance. It basically just makes a new copy of the function for each shading mode x each transparency mode, so 4x2 which is 8 slightly different functions and uses the correct one on each call. That increases binary size and icache pressure, but drops per triangle or per pixel if branches that hurt performance, so it’s an overall performance win. Benchmarked across a ton of different resolutions, models, shading modes, etc. (the benchmark by itself took like 2 hours to run)
Optimized the transparent cleanup path in the renderer After rendering the model in the transparent path, we have to resolve the transparent pixels, which basically just pastes in the pixels behind it and sometimes tints it based on how dark and what color the transparent material is (tinted glass will make the things behind it darker, normal glass will be mostly completely untinted). Before, the resolve function looped over every single pixel in the frame, even non-transparent and background ones. This is obviously wasteful. So I made it find the smallest box, in which all the transparent pixels of the whole frame fit and just looped over that. It recovered the overhead of the transparent resolve on models with smaller transparent parts, but it also made fully transparent or mostly transparent models slightly slower (it still basically loops over almost the whole screen on these types of models, so keeping track of the smallest bounding box while also still doing the same work as before made it a little slower). But the performance benefits for the average model outweighed the losses on rare fully transparent models. In the image, you can see the benchmark results versus the baseline.
Added TEXCOORD_1 support glTF sometimes authors a second TEXCOORD set (first one is TEXCOORD_0, 0 indexed numbering). The official spec only requires support for the first two TEXCOORD sets, even though there can theoretically be any number of them in a model. That said, major model exporters don’t author any more than the two sets, so to avoid extra work, I only added support for 0 and 1. (not merged into main yet, I want to polish it a little and maybe add KHR_texture_transform support on top of it first)
Added texture transform into the TEXCOORD branch and merged it into main Not that hard, just read it, pass it to the rasterizer and then display it. I did have a very sneaky bug in the loader that made the whole feature render wrong, where I just had to negate one value to fully fix it, but now everything fully works. Below you can see the Khronos test asset for texture transforms. (tick means fully working, clearcoat is not yet implemented so it doesn’t show as working)
Added proper OBJ bump map support OBJ bump maps are textures for simulating bumps and wrinkles on models. Blender used to author bump maps as normal maps for some reason, so I made it automatically detect if it’s a normal map disguised as a bump map and handle it well, since there are a lot of old Blender OBJ models in the wild. But it also handles bump maps as bump maps normally, so it’s basically the best of both worlds.
Completely removed gouraud shading mode Gouraud was previously the main shading mode, but now I’ve just completely removed it. It was by far the slowest, while not adding any actual value to the project. Blinn-phong lighting is faster AND it supports more features (normal maps, etc.), so there was just no point in keeping gouraud. Now that I’ve removed it, the project has less code to maintain and a faster default shading mode with more features.
Split the tests into sub-directories The test suite is now very long (20k LOC across 47 files), so i decided to split it into sub-directories instead of just having 47 files in one flat dir. It’s cleaner, more maintainable and looks better.
Pararelized the wireframe shading mode I did a bunch of small things alongside it, but the main feature for this devlog is the pararelization of the wireframe shading mode. It was previously fully single threaded, but it wasn’t that hard to pararelize, i just had to make the function it used to write into the framebuffer (draw_line) CAS atomic, to avoid race conditions. Now wireframe is the fastest shading mode in basically all scenarios. Below, you can see a performance benchmark (built into rasterminal using a flag) with wireframe mode on a super dense mesh and how the wireframe mode looks like (you can also cycle the colors).
Added a release workflow, manpage and changelog I added a github release workflow that works alongside the changelog and released the first pre-release version: v0.1.0-alpha.1 Also added a manpage and an install target to make and cmake that installs the binary, docs and manpage into the path.
Wasted 7 hours of my life Did a bunch of smaller cleanups and fixes, and then I tried to template the unlit and lit paths in the rasterize_flat function, which turned out to be a performance regression. Awesome.
Completely removed the shadow map Before, rasterminal built a shadow map on model load and displayed it during runtime. I now completely removed it, because it was slower during load, slower during runtime, sometimes looked broken on curved surfaces and added essentially no value. Here, the first picture is with the shadow map and the second is without.
Working on portability Did a bunch of small fixes and improvements in the last ~week. Right now I’m on vacation for the next couple of days, so I won’t be active. I am currently working on broader terminal and platform support, so older systems and terminals will be able to run cleanly with some fallbacks or will fail loud with a clear message about what isn’t supported.
Working on adding 256 color support Some older terminals can’t display full 24bit RGB colors and use a 256 color palette instead. I’m adding a fallback so the older terminals can still use rasterminal. It still calculates the full old RGB colors, but then just maps them to the nearest 256 color with LUTs. On a side note, I switched my terminal emulator from Kitty to Ghostty.
Working on terminal color capability detection I am adding automatic terminal capability detection, meaning that rasterminal will get the terminal type and either refuse to render on super old or “dumb” terminals, degrade on some terminals and render normally on modern ones.
Working on a –color compatibility flag The color terminal compatibility thing I was working on has landed in the branch, now I’m adding a –color flag to override the automatic capability detection for situations like ssh, where we almost always degrade to the 256 color pallete for maximum compatibility. So now you’re gonna be able to use the right color mode even if the automatic detection is wrong for your situation.
Changed the 24bit to 256 color palette conversion logic Until now, the conversion picked the closest color possible mathematically. But from testing on a bunch of different models, I’ve realized that it doesn’t actually look very close to the human eye. So I swapped it out for a different method, called CIELAB distance. Now it still doesn’t look perfect, but as a fallback for older terminals it’s close enough.
Finally merged color-fallback, I can move onto other things The branch is finally merged. I’ve accumulated a bunch of usability and code quirks and issues that i can finally get to now that the branch is merged. So now I’ll be reworking all the CLI flags, camera and other components. And we also passed the 700 commit mark with this merge!
Did a bunch of small code quality and usability improvements Fixed a Windows bug that crashed the program on model sizes bigger than 2GB, improved the orbit usability (fixed mouse drag behavior when models are turned upside down), and did a few cleanups and fixes in the CLI parsing. I’m planning on adding a few CLI flags that I think can be very useful for some people, specifically better spin settings, starting camera angle/zoom control and a few more.
Added –spin-speed and –spin-direction flags Added CLI flags for the spin speed and direction. The speed is in deg/s and the directions is simply left or right. Here’s what 1000 deg/s looks like spinning to the right:
Added more CLI flags for startup customizability Added flags to set the camera pitch, yaw and zoom on startup. Now every runtime-settable variable can be set during startup through the CLI. The R button now resets the state to the CLI set state, not to factory defaults.
So, i found two memory bugs in a widely used terminal input library I was researching terminal input libraries to use for this project because my current approach was so buggy that it wasn’t worth fixing. Both of them are memory bugs in the libtermkey library. There are forks of the lib with this fixed, but since many projects still rely on this lib, i submitted them anyways. I’ve also confirmed that the bug is present on my machine on Ubuntu 24.04 LTS on Neovim, because it links the vulnerable shared library. I didn’t mark them as CVEs (hopefully that isn’t a problem). If anyone want’s to look at the bug reports, they are at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1142891 and https://bugs.launchpad.net/ubuntu/+source/libtermkey/+bug/2161916
Working on completely rewriting the current input parsing handling The current input handling is subpar at best; it interprets a lot of random keys as escape, which currently quits the program (This will also be changed to Q and Ctrl+C only. Kind of a no-brainer since this is the more standard choice for TUIs - for example btop - and it also means I don’t have to deal with the headache of distinguishing function keys and others from escape) and has a lot of other quirky behavior that needs fixing. I’ll also try to improve robustness against malformed input like a leaky SSH session. There are a lot of various edge cases and situations where you have no way to distinguish real input from malformed input. This is all a very major pain in the ass. And I thought figuring out the raw mode output would be the hard part. And after all this, I’ll end up with way less attention than strictly slower, less robust competitors, just because they already have an audience from other projects. I bet nobody will even read this. I’m basically talking to myself right now. Or maybe, just to spite me, the algorithm will push this more than my other devlogs.
Still working on the input parsing system It is very hard and I keep finding bugs and reasons to redesign it. I’m in pain. I do think I’m getting closer to the final robust design.
Finally committed and pushed the input rework Tested it on both linux and windows and everything seems to work. No inputs interpreted as other inputs, all edge cases handled, just works. Finally can move onto other things.
Did a smaller fix and added a pretty big feature First, let’s talk about the small fix: I Fixed a super long model name showing up in the HUD in it’s full length, often blocking out other HUD elements. Previously, the HUD would display a model name of any length. Now there’s a hard cap of 24 chars, with any name longer than that truncated (middle style truncation) to fit into that limit. And now the big feature: Added a first person noclip-style camera mode. It’s accessed with the –first-person flag and let’s you explore the model as a floating camera (not bound like the default orbit camera). It was honestly easier to implement than I thought it would be. With it, I added two new keybinds special to the first person mode - E and V for going up and down. They don’t do nothing in orbit mode. Also added a second –first-person-speed flag for controlling the initial movement speed. It is also controllable during runtime with scrolling or +/- (I didn’t know what to bind these to in this mode since you can’t zoom like in orbit mode and this was the only place where they fit). In the photos, you can see some angles taken in the first person mode that weren’t possible in the default orbit mode.
Completely redesigned and rewrote the HUD The HUD used to be just a single line at the bottom of the screen aligned to the left. It looked pretty bad, but it did tell the user everything they needed to know. [picture 1] First, I added model name sanitization, so models with control bytes like newline ( \n ), line feed or other symbols like emojis can’t break the whole program when trying to display them in the HUD. Then, I completely redesigned the whole HUD to look better and be more robust, while still telling the user everything they need to know. I went with this design [picture 2]: On the left, you only have the model name. In the middle, first you have the current shading mode (highlighted in cyan), then the lighting mode in plain white and then the background color in gray. All three middle indicators are separated with a dot and are different colors, so nobody can confuse them. On the right, there’s 3 boolean indicators: spin (if the model spin is on), backface cull (if it’s currently culling backfaces) and texture (if it’s showing the texture, isn’t there at all on models without a texture). They are gray if inactive and cyan if active. The last thing on the right is just the fps number. There can also be optional indicators: Wireframe color (in the middle, after the shading mode) which only shows up in wireframe mode. [picture 3] First person speed multiplier (on the right, between the bools and the fps number) which shows up only in first person mode. [picture 4] I also made each “island” cleanly disappear when the terminal’s width is too low instead of just slowly getting cut off letter by letter. I think this design looks better, less cluttered and is pretty easy to understand at a glance. I would very much appreciate a star on GitHub!
Added issue templates + contributing documentation Added templates and a config for submitting GitHub issues, for both bug reports and feature requests. Also added a CONTRIBUTING.md for clear instructions on how to make, structure and audit code contributions. (tests, linters, formatting, etc.) I tried to make some optimizations to the renderer by auditing the compiler generated assembly and looking for inefficiencies, but everything i tried turned out to actually hurt performance. And GitHub actions decided to have a major outage right when i pushed the commits, so that’s awesome
Minor comment cleanup Just did some comment cleanup: Deleted redundant comments and why comments Removed separator comments Compressed or rewrote some really long comments (without removing the info they give)
Working on adding support for the Kitty protocol Some modern terminals like Kitty and Ghostty have support for the Kitty protocol. It’s a feature that allows you to display high resolution content like images and videos in the terminal without it looking super pixelated. There’s also the Sixel protocol, which is basically the same thing but a little worse and more widely supported (even Windows terminal has it). I’ll add Sixel after i merge Kitty to main. It is very clearly a worthwhile feature and I have been planning to add it from the start of the project. Today I finally decided that it’s time. Most of the work is already done on the branch and i’m just polishing out the bugs and issues before I merge. In the photos, you can see the comparison between using just the block characters and using Kitty. It is a night and day difference. Although the performance isn’t great at that high of a resolution, but I’m still working on optimizing that.
Found a bug in Ghostty’s kitty protocol handling Ghostty is a modern and fast terminal emulator that i personally use. While testing the kitty protocol feature in rasterminal, I found a Ghostty bug that lagged my whole computer after a few minutes. I tested it in Kitty (terminal emulator) and there it worked fine. I looked at Ghostty’s code vs Kitty’s, found the bug and reported it to the Ghostty maintainers. Mitchell himself (the creator) fixed it in like 2 hours. Honestly I’m kinda sad I didn’t get to become a contributor and fix the bug, but since it was a small fix and I already described it in the issue, I get why Mitchell just fixed it in main. Here’s the full issue: https://github.com/ghostty-org/ghostty/discussions/13719
Fully merged and done with Kitty Finally completed the kitty protocol implementation. It is kinda slow, since the resolution is so much bigger, so I will try to optimize the high-res performance even more. So now the next two big milestones are: Add Sixel on top of kitty, that’ll be a lot of work Optimize the rasterizer even more I was thinking of maybe adding gpu rendering as an option for super large meshes or high-res scenarios, but idk. I’ll definetly keep the pure cpu renderer for computers without gpus, but I’m not sure about a gpu implementation. It would be hard to do, less portable and it might not even work that well.
Working on adding full Sixel support Working on adding support for the other mainstream terminal pixel protocol of the main two - Sixel. Already did fully implemented the kitty protocol last time, so once I’m done with this one, I’ll be done with terminal protocols (at least for the near future, hopefully). There are some other ones like the iterm2 protocol, but that one’s pretty rare and I won’t add it unless I really don’t have anything better to do. It’s basically done, just need to polish it and test it on a bunch of terminals and operating systems to make sure everything works before merging.
Fully merged sixel Fully merged the sixel protocol implementation. Works on all platforms everywhere that supports it. So now both high-res terminal protocols done. Moving onto other minor things and especially performance.
Working on improving performance With the addition of the high-res protocols, the target resolutions quickly went from hundreds or thousands of pixels to millions. So I now desperately need to improve performance. So far it’s looking promising: A whole model covering the camera 6 moving at 4k went from about 8 fps to 20-30 fps. Not ideal yet, but I think we’re on the right track. Super dense meshes (more than 2 million polygons) improved 2-3x Meshes with transparent parts improved about 2x While these wins may seem really big (they kinda are), the jump in resolutions still means they are barely usable interactively. I do want to add gpu acceleration later (with the cpu path as a fallback), but until then I want to make it as fast as I possibly can.
My reported bug in libtermkey has been fixed in the newest version Just got an email from one of the maintainers that the crash bug i reported a month ago was fixed in the new release. libtermkey is a terminal input parsing library that I considered using and found a crash bug in. The bug was already fixed in neovim’s fork of the library, so i just pointed the maintainers at that fix. For anybody interested, here’s the issue link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1142891
Still optimizing… Spent the first ~7 hours trying to find microoptimizations and each one was either a wash or worse somehow. The compiler works in mysterious ways. At some point, I just gave up and let Claude have a go at the optimizing. Surprisingly it actually came up with a lot of interesting optimization techniques and solutions that I definitely couldn’t have come up with on my own. But it found so much, that the whole diff adds 5k lines of code. So now I’ll be cleaning up, testing, and maybe further optimizing that diff…
Finally merging the performance branch It’s finally time to merge the performance branch. I basically redesigned the whole renderer and rasterizer around high resolution workloads, where it would still choose the old high-poly paths where they were faster. Even snuck in some SSE2 SIMD code (picture), although I will probably be switching to a dispatch SIMD library like Google’s Highway. Not entirely sure it will be Highway or even if I will do that yet, that depends on the code complexity and before/after benchmarks.
Cleanup and restructuring changes After I just merged three big feature branches (kitty and sixel graphics protocols and the high-res performance branch), I needed to do some overdue cleanup and refactoring. And so I did: Collapsed the super long changelog entries into way more readable and legible points Restructured the src directory into multiple subdirectories because it had like 50 files already Sadly completely removed the Make build system, so now you can only build with CMake (CMake is very much evil and even more evil but it’s the only one of the two that supports windows and I was tired of managing two build systems) Removed the –graphics-scale flag, so now everything renders at native resolution And some small docs and comment cleanup
Working on assimp integration Yop, I’m adding the Open Asset Import Library as a fallback for any model formats that aren’t natively supported with their own dedicated loader (only ones with dedicated loaders are glTF2, PLY, STL and OBJ). I’m still keeping the dedicated loaders, because they are more feature-complete, to-spec and wayyy faster (especially the glTF one). I added it because I feel like for a 3D model viewer, support for many formats, even niche and obscure ones, is pretty important, even though nobody might use them. This roughly doubled compile time and almost quadrupled binary size, which also made CI take way longer (of course). It somehow made the MacOS runners take 50 minutes to compile (from the previous 3 minutes), but I fixed that by bounding the number of processes CMake can spawn to the number of threads on the runner (previously was using -j which spawns as many as it wants and it was spawning about 230 of them). I’m still testing how it handles various model formats and trying to find any reachable segfaults.
Still working on the assimp intgration Currently trying various models from all the different model formats that assimp loads. So far found a segfault, some weird behavior and integration mistakes that I made. Also found a small bug in assimp itself, for which I’ve submitted the PR with the fix to their GitHub repo. For anyone interested, here’s the PR: https://github.com/assimp/assimp/pull/6799
Fuzzing my assimp wrapper I’m trying a bunch of hand-crafted models from all the formats that I can load and trying to find things that dont load or render properly. Also had AI write me a simple fuzzer in python and I’m just letting it run for a few hours. Also auditing the assimp loader paths against my wrapper to find any format specific behaviour that should be handled. I’ve already found a bunch of things and I’m still finding more. Assimp has a lot of weird quirks and issues that I keep running into. Honestly kinda regretting the decision to integrate it, but since I’m already so deep in, I’ll just keep going.
Merged the full assimp integration into main I really don’t have much to say here, I’ve already put all the info about the branch into the past devlogs. All the formats work and the wrapper is very sturdy. I’ve found more bugs in assimp itself than my code (devlog on that soon). So, rasterminal can now load basically any 3D model you throw at it. Some of the formats assimp supports are so niche, I’ve never even heard of them.
Cutting a release The repo is in a pretty complete and polished state, so I’ll cut a release here. This will also probably be the last release before I ship, so I’m making sure that nothing is broken and everything works on every platform. I’ve still got a lot of work to do though, even after the end of stardance, like animations, glTF PBR, format completeness for every format, GPU acceleration, etc.
Found a bunch of terminal cleanup gaps Most of them are Windows or cmd.exe specific (nothing ever works on Windows), but some are present on POSIX too. The Windows specific ones are: cmd.exe for some unknown reason doesn’t turn off the raw input sequences, so arrow keys don’t work like they should, even though I explicitly turn it off (????????) (I hate Windows, they always have to do something unexplainable for no reason just so your code doesn’t work as it should) when you terminate the program with ctrl+c or ctrl+break while actively dragging the model around, it sometimes leaks mouse escape sequences into the next prompt bunch of other weird small stuff that nobody cares about And the few on POSIX are mostly ctrl+z suspend/resume behaviour not recovering the terminal and the same thing with ctrl+\ (SIGQUIT). I’m still working on fixing these. Most of the windows ones are already fixed, but I haven’t even started with the linux/POSIX ones. I have postponed the planned release to when I fix these + any other issues I find.
I HATE WINDOWS Windows just doesn’t work. It doesn’t work. Nothing works on Windows. Everything breaks. I don’t get it. THE UNIT TESTS PASS ON WINDOWS CI BUT WHEN I ACTUALLY RUN THE TESTS ON WINDOWS IT FAILS????? HOW IS THAT EVEN POSSIBLE. The release is now definitely getting delayed by at least a week because I keep running into more and more and more and more and more and more and more and more and more issues. I hate Windows. Microslop is the only company that could mess up a basic terminal emulator. And I also have to reboot my PC every time I fix something and push it and then reboot to get back to linux. this is torture. At one point I tried to do it on a Windows VM on linux but that was too slow so I just gave up.
Merged the full Windows console restoration branch My nightmare is over. I hopefully won’t have to deal with Windows for a while now. Summary of what is now fixed/handled on Windows: Ctrl+C, Ctrl+Break and Q exits fully recover the terminal’s state Ctrl+C and Ctrl+Break don’t leak mouse escape sequences into the next prompt if you terminate while actively dragging a model A bunch of other minor Windows or cmd.exe specific quirks Only thing that isn’t handled (didn’t find a good way to handle it) is task manager “end process”. It kills the program without cleaning up and sometimes freezes the shell.
Fully fixed and merged the first POSIX cleanup item Well, would you look at that! That took significantly less time than the Windows fix. It is partly because it was a smaller fix and only part whole POSIX fix, while the Windows one was the whole thing and also the foundation had already been laid out from the Windows work and I just integrated the POSIX path into that, but it is also very much because Microsoft is a horrible, terrible company that can’t make good software. I mean, look at GitHub, they have been going downhill ever since they got acquired by Microsoft. Now that I got that out of my system, here’s what was fixed: If the program cannot enable raw mode at startup, it safely fails instead of continuing and corrupting the terminal state If the cleanup gets interrupted, it retries cleanup so it doesn’t leave the terminal state corrupted after one failed attempt Onto the next POSIX fix: handling SIGQUIT and SIGHUP.
Added handling for SIGINT, SIGTERM, SIGQUIT and SIGHUP I don’t really have much to say here, I just added the full per-spec handling for all these. Only remaining POSIX-only gap is now SIGSTOP/SIGCONT (stop/resume process). I’m also starting school now, so I’ll be working on this less.
Working on SIGSTOP and SIGCONT handling SIGSTOP and SIGCONT are POSIX signals for stopping and resuming a running process. I’m working on adding handling for these, so you can safely pause and unpause rasterminal at any time. This is a lot of work, since until now, we just set up the terminal on program start and cleaned up when the program exited. There’s a lot of quirks and weird scenarios that I have to handle, for example if another signal gets sent while cleaning up the terminal for SIGSTOP. I’m trying to catch as many edge cases by just doing random things while using the program and also with the help of AI to come up with potentially uncaught scenarios.
Did some polish and cleanup of the platform layer Did final polish and cleanup of the platform layer since I want to actually finally cut a release relatively soon and I just did a lot of work there. Fixed things like useless tests, outdated or wrong comments and some platform specific quirks. Probably actually gonna cut a release soon (this time for real). Also added early rejections for BVH and CSM files, since they contain no model geometry (they can’t currently be displayed at all) and documented the change. The code is basically done (hopefully, I really don’t want to find another big gap that’s gonna take a week to close), I just want to correct anything wrong in the README, changelog, manpage or help menu and maybe make them look a little better before cutting a release and shipping.
Last pre-release checks and cleanup I’m finally ready to release v0.1.0-alpha.2. Only notable thing I changed here is that I changed the default thread count: It now defaults to hardware concurrency everywhere. Other than that, I of course did final documentation checks and fixes and now I’m just waiting for CI to pass so I can tag it and let the release workflow do the last step. So this is hopefully the last devlog before my ship!
Refactored the platform layer The whole platform layer was just one file until now. Since I did a lot of work on it recently, it grew to over 2400 lines of code. It was super confusing and disorienting. So I decided to refactor it (split it) into 8 files, based on what they handle: console.h - saving/restoring terminal state control.h - termination signal handling file.h - file operations (64bit) input_reader.h - handling input (not parsing, that is it’s own file) shared_memory.h - shared memory handling for the kitty protocol terminal_io.h - writes output to the terminal terminal_query.h - querying the terminal for things like graphics capability, etc. timing.h - frame timing and sleeps
Miscellaneous fixes and improvements Fixed two races in platform code (one MacOS, one Windows) Removed build flags that disabled some compiler security hardening at the cost of a little performance Fixed the test framework to not freak out on NaN in near assertions Improved thread launching and handling in loaders and renderer So overall just boring fixes and improvements, nothing special.
Code quality and CI improvements Finally did the long overdue main loop refactor. The main loop is now way shorter, more readable and more testable. I just split off some of the main loop’s work into it’s own modules, which made them way better looking and also, since they are now standalone modules, actually testable. A big win for repo structure. In the process, I also replaced the input handling’s long if chain that made each character do it’s job with a switch statement. It’s more readable and theoretically faster, although since I compile it with -O3, it probably made no difference or an unnoticeable one at best. I also finally fixed the super long CI times. Until now, CI used to take ~50 minutes (depending on how fast the GitHub runner was) because of cppcheck. Everything else finished in under 10 minutes, but cppcheck stalled it for an hour. It was stalling in mesh_assimp.cpp (the assimp wrapper) for most of it’s runtime. I always thought it was because assimp is a very large library. So I experimented with it a little. I included everything I include in the wrapper into a test file with a little code and ran cppcheck on that. It finished in less than 10 seconds. Eventually, I found out it was somehow taking that long because the main loader function was too long and handled too much by itself. So i just refactored it into 3 separate functions, without changing the behavior at all. Somehow, I still don’t get why, it reduced the whole cppcheck run to 9 minutes. a more than 5x improvement, just because I split a function into more functions. I’m not complaining, but it’s definitely weird. CI is now way faster and adding new things is gonna be way smoother now.
Ships:
rasterminal rasterminal is a 3D model viewer in the terminal Why i decided to build it The original idea didn’t really have any big inspiration, I’ve just always been fascinated by the inner workings of 3D and how that all works. I’ve been wanting to build a project involving 3D for a while and I didn’t want to make just another program that uses libraries and GPU drivers to do all the work. So I came up with the idea: a software rasterizer that renders in the terminal! There are lots of TUIs and lots of boring old software rasterizer projects, so I just combined the two into something unique. And over time, I realized I could make it an actually useful tool, with no real competition: a 3D model viewer in the terminal. Sure, there are some similar projects on GitHub (like taigrr’s trophy), but none are actually usable with heavier models or support pixel graphics. What I learned I learned a lot. I really mean a lot. Anything from math and rendering to how terminals work and how to control them using escape sequences. I don’t want to sit here and name everything I learned over the period of the last 5 months, but I can confidently say that this project really taught me how much work goes into everyday software and how to actually develop and maintain a project professionally. The future of rasterminal The whole project is very far from done. You can see that from the latest release version: v0.1.0-alpha.2. I’ve got a lot of work to do and I’ve roughly got the major landmarks mapped out. Main things I definitely want to change/add at some point before v1 are: Add animation support (currently can only render still meshes) Complete the renderer (complete support for basically every feature of every format that makes sense to support) Add optional GPU acceleration (after I’m satisfied with everything else) Hardware / OS support Supports every major OS (Windows, Linux, MacOS, and any other POSIX-based OS, so practically everything), and every CPU that I could think of (any architecture, 32 or 64bit). You would have to actually try a to find a platform that it doesn’t support (most of the unsupported hardware are big-endian systems, which are basically phased out completely). This is one of the main goals of the project, so (almost) any modern machine with a terminal can run it. Special thanks Special thanks to anyone who followed, liked, helped, or otherwise supported the project in any way. I wouldn’t have had the motivation to push it this far if it wasn’t for you guys....
|
1793105289.4980307
|
1793191689.4980307
|
|
66426
|
raspberry pi weather display by @pcsef40 | Stardan raspberry pi weather display by @pcsef40 | Stardance...
|
pcsef40
|
0
|
1.28
|
0
|
[]
|
[{"post_id": 74995, "ts": "202 [{"post_id": 74995, "ts": "2026-09-28T20:04:50Z", "hours": 1.285, "text": "some cable management… as you can see i dont have much to work with"}]...
|
Title: raspberry pi weather display by @pcsef40 | Title: raspberry pi weather display by @pcsef40 | Stardance
Devlogs:
some cable management… as you can see i dont have much to work with...
|
1793098349.0572212
|
1793703149.0572212
|
|
68336
|
raspberry pi hole! by @emilia-fish | Stardance
|
emilia-fish
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: raspberry pi hole! by @emilia-fish | Starda Title: raspberry pi hole! by @emilia-fish | Stardance...
|
1793119984.7849462
|
1793724784.7849462
|
|
48218
|
rario by @Revse | Stardance
|
Revse
|
0
|
1.57
|
0
|
[]
|
[{"post_id": 50322, "ts": "202 [{"post_id": 50322, "ts": "2026-08-19T14:24:29Z", "hours": 0.5072, "text": "finally a level selection scene."}, {"post_id": 50267, "ts": "2026-08-19T12:58:42Z", "hours": 0.7314, "text": "Finally a working UI."}, {"post_id": 48925, "ts": "2026-08-17T14:19:40Z", "hours": 0.3333, "text": "Creating and Designing Rario."}]...
|
Title: rario by @Revse | Stardance
Devlogs:
Creat Title: rario by @Revse | Stardance
Devlogs:
Creating and Designing Rario.
Finally a working UI.
finally a level selection scene....
|
1792544054.7989721
|
1793148854.7989721
|
|
68900
|
raqccuqi by @kelp | Stardance
|
kelp
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: raqccuqi by @kelp | Stardance
|
1792475423.4764626
|
1793339423.4764626
|
|
45782
|
rangemax by @THE_J_strong | Stardance
|
THE_J_strong
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: rangemax by @THE_J_strong | Stardance
|
1792637419.1068316
|
1793242219.1068316
|
|
31927
|
rangefinder by @Serg | Stardance
|
Serg
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: rangefinder by @Serg | Stardance
|
1792579654.258831
|
1793184454.258831
|
|
59491
|
randomtogettoshop by @aryanscode | Stardance
|
aryanscode
|
0
|
1.08
|
0
|
[]
|
[{"post_id": 63694, "ts": "202 [{"post_id": 63694, "ts": "2026-09-07T17:04:16Z", "hours": 1.0836, "text": "this is a random ai project im logging to unlock shop"}]...
|
Title: randomtogettoshop by @aryanscode | Stardanc Title: randomtogettoshop by @aryanscode | Stardance
Devlogs:
this is a random ai project im logging to unlock shop...
|
1792799616.0580552
|
1793404416.0580552
|
|
56111
|
randompad by @Yukelinlin | Stardance
|
Yukelinlin
|
0
|
0.83
|
0
|
[]
|
[{"post_id": 58012, "ts": "202 [{"post_id": 58012, "ts": "2026-08-30T11:00:00Z", "hours": 0.8333, "text": "trying to follow the guide,its abit confusing but i got it done anyways!"}]...
|
Title: randompad by @Yukelinlin | Stardance
Devlo Title: randompad by @Yukelinlin | Stardance
Devlogs:
trying to follow the guide,its abit confusing but i got it done anyways!...
|
1792648277.846542
|
1793253077.846542
|
|
36028
|
randomgenerals AI by @imrxne1 | Stardance
|
imrxne1
|
1
|
16.93
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-09T19:42:20Z", "hours": 10.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "A chat, coding, image and diagram assistant running on one free Oracle VM — two ARM cores, 11.9 GB RAM, no GPU. Routes between Groq, OpenRouter and local Ollama so one channel being rate-limited is a degradation, not an outage. Includes accounts with two-factor auth, a sandboxed Python runner, web search, file and image reading, and an installable PWA.", "repo": "https://github.com/imraneadib1-dot/randomgenerals", "demo": "https://randomgenerals.com"}]...
|
[{"post_id": 72403, "ts": "202 [{"post_id": 72403, "ts": "2026-09-22T20:59:32Z", "hours": 5.9989, "text": "so far so good i am seeing some results"}, {"post_id": 66648, "ts": "2026-09-12T14:36:31Z", "hours": 0.9278, "text": "my AI may not be the best, but it is also free and good"}, {"post_id": 64994, "ts": "2026-09-09T19:23:31Z", "hours": 2.9472, "text": "need a free ai to help ya? gotchu checck random generals AI free and a good companion and also it was a pain in the abs to make, still fixing some bugs but pliz make sure to check it out :)"}, {"post_id": 64259, "ts": "2026-09-08T15:07:24Z", "hours": 6.8839, "text": "groq rate limit almost killed my whole app so i built randomgenerals.com. its an ai assistant, chat + code + image gen + diagrams. runs on a free oracle vm, 2 arm cores no gpu. flask app that does the website, the pwa and the backend for the desktop version. accounts, credits, emails, dashboard, all of it. ok so the bug. groq free tier is 8000 tokens per minute. not per request. per minute. for the entire key. every single user on my site sharing that. and it counts your prompt AND the reply you asked for as one number together. i wasnt checking that anywhere lol so if a chat got long enough (like 5400 tokens) it would just stop working. forever. you hit retry and it builds the same too big request and gets refused again. same error every time. only way out was starting a new chat and nobody knows to do that. my first idea was just make the replies shorter. bad idea. thats the thing people actually came for. so now it drops old messages first and only shortens the reply if that wasnt enough. forgetting what you said 6 messages ago is annoying. not getting an answer is worse. then i found another one. i was never checking finish_reason so when a reply hit the token limit it just stopped mid sentence and looked completely normal. and the api returned 200 every time so my logs were clean. no clue how long that had been happening ngl 126 commits so far. randomgenerals.com"}]...
|
Title: randomgenerals AI by @imrxne1 | Stardance
Title: randomgenerals AI by @imrxne1 | Stardance
Devlogs:
groq rate limit almost killed my whole app so i built randomgenerals.com. its an ai assistant, chat + code + image gen + diagrams. runs on a free oracle vm, 2 arm cores no gpu. flask app that does the website, the pwa and the backend for the desktop version. accounts, credits, emails, dashboard, all of it. ok so the bug. groq free tier is 8000 tokens per minute. not per request. per minute. for the entire key. every single user on my site sharing that. and it counts your prompt AND the reply you asked for as one number together. i wasnt checking that anywhere lol so if a chat got long enough (like 5400 tokens) it would just stop working. forever. you hit retry and it builds the same too big request and gets refused again. same error every time. only way out was starting a new chat and nobody knows to do that. my first idea was just make the replies shorter. bad idea. thats the thing people actually came for. so now it drops old messages first and only shortens the reply if that wasnt enough. forgetting what you said 6 messages ago is annoying. not getting an answer is worse. then i found another one. i was never checking finish_reason so when a reply hit the token limit it just stopped mid sentence and looked completely normal. and the api returned 200 every time so my logs were clean. no clue how long that had been happening ngl 126 commits so far. randomgenerals.com
need a free ai to help ya? gotchu checck random generals AI free and a good companion and also it was a pain in the abs to make, still fixing some bugs but pliz make sure to check it out :)
my AI may not be the best, but it is also free and good
so far so good i am seeing some results
Ships:
A chat, coding, image and diagram assistant running on one free Oracle VM — two ARM cores, 11.9 GB RAM, no GPU. Routes between Groq, OpenRouter and local Ollama so one channel being rate-limited is a degradation, not an outage. Includes accounts with two-factor auth, a sandboxed Python runner, web search, file and image reading, and an installable PWA....
|
1793144895.1166584
|
1793231295.1166584
|
|
43503
|
random.randint(0,1) by @rainbowtailor84 | Stardanc random.randint(0,1) by @rainbowtailor84 | Stardance...
|
rainbowtailor84
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random.randint(0,1) by @rainbowtailor84 | S Title: random.randint(0,1) by @rainbowtailor84 | Stardance...
|
1792551011.4273207
|
1793155811.4273207
|
|
59874
|
random-project-i-do-work-on-so-i-can-get-the-daily random-project-i-do-work-on-so-i-can-get-the-daily-5-minutes-needed-for-the-streak-easier by @SeradedStripes | Stardance...
|
SeradedStripes
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random-project-i-do-work-on-so-i-can-get-th Title: random-project-i-do-work-on-so-i-can-get-the-daily-5-minutes-needed-for-the-streak-easier by @SeradedStripes | Stardance...
|
1793029949.5815482
|
1793634749.5815482
|
|
36274
|
random website by @onetwothree | Stardance
|
onetwothree
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random website by @onetwothree | Stardance
|
1792540278.4948225
|
1793145078.4948225
|
|
29717
|
random twitch bot by @alexqwsa | Stardance
|
alexqwsa
|
0
|
4.38
|
0
|
[]
|
[{"post_id": 64970, "ts": "202 [{"post_id": 64970, "ts": "2026-09-09T18:33:04Z", "hours": 4.3772, "text": "hi look at this image its a demo of what it does it currently does these stuff: >teto –> pulls user data stuff from ch.tetr.io (it currently pulls my username in it but it’ll be changed to be usable later) >swag –> same deal with the >teto command but for swag.nomaakip.xyz main instance doesnt exist anymore but theres a source code for it (same stuff with the username but on swagsocial ) not in the image but why not mention it: buh –> buh and more… (i think) also i started from a example code from the twitch developer documentation just to let you know, but i wanna add more stuff for it and change some stuff also i forgot to make some commits on the repository lmao im sorry"}]...
|
Title: random twitch bot by @alexqwsa | Stardance
Title: random twitch bot by @alexqwsa | Stardance
Devlogs:
hi look at this image its a demo of what it does it currently does these stuff: >teto –> pulls user data stuff from ch.tetr.io (it currently pulls my username in it but it’ll be changed to be usable later) >swag –> same deal with the >teto command but for swag.nomaakip.xyz main instance doesnt exist anymore but theres a source code for it (same stuff with the username but on swagsocial ) not in the image but why not mention it: buh –> buh and more… (i think) also i started from a example code from the twitch developer documentation just to let you know, but i wanna add more stuff for it and change some stuff also i forgot to make some commits on the repository lmao im sorry...
|
1792536488.565265
|
1793141288.565265
|
|
6309
|
random stuff by @lcorcione | Stardance
|
lcorcione
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random stuff by @lcorcione | Stardance
|
1792547575.3363447
|
1793152375.3363447
|
|
1574
|
random rogue like video game by @bracdyn | Stardan random rogue like video game by @bracdyn | Stardance...
|
bracdyn
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random rogue like video game by @bracdyn | Title: random rogue like video game by @bracdyn | Stardance...
|
1792788707.7537093
|
1793393507.7537093
|
|
34395
|
random code by @4net_E | Stardance
|
4net_E
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random code by @4net_E | Stardance
|
1792698680.3368304
|
1793303480.3368304
|
|
59209
|
random by @jacqueshealley | Stardance
|
jacqueshealley
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random by @jacqueshealley | Stardance
|
1792788702.6163225
|
1793393502.6163225
|
|
66296
|
random bot by @irlight-1 | Stardance
|
irlight-1
|
0
|
0.32
|
0
|
[]
|
[{"post_id": 74486, "ts": "202 [{"post_id": 74486, "ts": "2026-09-27T14:21:25Z", "hours": 0.3197, "text": "finished the tutorial, surprised it worked since i suck at coding"}]...
|
Title: random bot by @irlight-1 | Stardance
Devlo Title: random bot by @irlight-1 | Stardance
Devlogs:
finished the tutorial, surprised it worked since i suck at coding...
|
1793098163.213285
|
1793702963.213285
|
|
27636
|
random boat game. by @whael | Stardance
|
whael
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: random boat game. by @whael | Stardance
|
1792533304.0756829
|
1793138104.0756829
|
|
44342
|
ramy by @Ramithu | Stardance
|
Ramithu
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: ramy by @Ramithu | Stardance
|
1792583292.0616577
|
1793188092.0616577
|
|
57654
|
ramenHUB by @heian | Stardance
|
heian
|
0
|
3.53
|
0
|
[]
|
[{"post_id": 64207, "ts": "202 [{"post_id": 64207, "ts": "2026-09-08T13:15:25Z", "hours": 0.3206, "text": "Finished the README to the ramenHUB! Shared and shipping it now! https://oshwlab.com/minayeh1347/project_zzwrytvq"}, {"post_id": 63899, "ts": "2026-09-07T22:44:59Z", "hours": 3.2094, "text": "Finished the ramenHUB! Lots of learning how to use EasyEDA! In some ways, quite a bit easier than using KiCad or Altium, in other ways a bit more difficult. I do miss just knowing where different commands are, but I think it’s a bit easier to route differential pairs and order from JLCPCB. Had a lot of fun with silkscreen art (and a bit of hidden copper art too)!"}]...
|
Title: ramenHUB by @heian | Stardance
Devlogs:
Fi Title: ramenHUB by @heian | Stardance
Devlogs:
Finished the ramenHUB! Lots of learning how to use EasyEDA! In some ways, quite a bit easier than using KiCad or Altium, in other ways a bit more difficult. I do miss just knowing where different commands are, but I think it’s a bit easier to route differential pairs and order from JLCPCB. Had a lot of fun with silkscreen art (and a bit of hidden copper art too)!
Finished the README to the ramenHUB! Shared and shipping it now! https://oshwlab.com/minayeh1347/project_zzwrytvq...
|
1792929134.941143
|
1793793134.941143
|
|
9099
|
ramen by @axie | Stardance
|
axie
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: ramen by @axie | Stardance
|
1792536602.0985174
|
1793141402.0985174
|
|
23277
|
rainwall by @angelcube | Stardance
|
angelcube
|
1
|
21.28
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-21T23:38:16Z", "hours": 11.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "🌈 rainwall is done! This is a CLI utility that uses the weather outside to select a matching image as your wallpaper. This was my first time using Deno, and I feel like it’s got its pros and cons. I learned so much in manipulating the actual OS through TypeScript, and I feel much more confiident in it as a scripting language now! I wasn’t able to test on any other architectures, so please submit feedback as needed! You can download rainwall via JSR , GitHub , or with the PKGBUILD !", "repo": "https://github.com/weightedangelcube/rainwall", "demo": "https://github.com/weightedangelcube/rainwall/releases/tag/0.1.0-alpha.stardance"}]...
|
[{"post_id": 16656, "ts": "202 [{"post_id": 16656, "ts": "2026-06-27T02:34:30Z", "hours": 3.6031, "text": "DEVS OF STARDANCE, I need YOUR HELP! Setting wallpapers for multiple monitors on macOS is tediously hard! There’s gotta be a Swift application in the middle accepting this call, so… Would you rather: a Swift library bundled within the (TypeScript) application to interact with Cocoa and handle setting the wallpaper a dependency on another CLI tool like desktoppr for this? LET ME KNOW IN THE COMMENTS! Or something. I’m not a YouTuber"}, {"post_id": 14727, "ts": "2026-06-23T22:46:16Z", "hours": 1.7067, "text": "Today I learned that the CIEDE2000 algorithm never worked in the first place and was outputting numbers opposite to on the colour wheel. Why? I have no clue and I don’t intend to find out, because I’ve decided I’ve had enough of typing in sine and cosine and was just going to use the library colordx instead. The whole project was refactored, including the analyze API, so if you’ve had an index file generated previously make sure to regenerate it!"}, {"post_id": 14625, "ts": "2026-06-23T20:06:21Z", "hours": 4.0125, "text": "I just spent four hours doing genuinely the most annoying thing on the planet: building for Windows . I found a neat little Stack Overflow thread that seemed to do what I wanted it to: write a PowerShell script that could set the wallpaper on Windows machines. Not too shabby, I thought. I could probably ask one of my friends to test on their machine. It wouldn’t take too long, maybe half an hour at max. Boy, was I wrong. I forced the poor bloke to install ImageMagick, then sent him a CI build. We gave the program a test run, and I ran into my first real challenge: paths. Oh my God, I hate Windows paths. Nothing would work—making folders, writing files, any of that until I replaced every single forward slash with Deno’s fromFileUrl . And being a person with not so great memory, I sent over at least five builds before I fixed every single path in the way. Honourable mentions include: I mistook configPath for cachePath fromFileUrl(\"C:/..\") because that is definitely a file:/// URL path.join(`${imageDir}, ${image.name}`) Part 2: PowerShell. I thought ( ) that zx would run on PowerShell out of the box. Nope! It depends (and it actually says this in the README too) that it depends almost exclusively on Bash and Bash escaping. There’s a usePowerShell() command, but I genuinely don’t have the energy right now to figure out the refactors required to make that work—on someone else’s machine . So I make the guy install Git Bash, and also Deno so I can just send him diffs instead of having to send the Full Deno Runtime™ every time I had a new build. At this point, rainwall-analyze finally works (yay!) and dumps the correct paths to the cache folder. We run rainwall-apply , I find four new cases of paths I did not fix, and I go back into VSCode hell. Part 3: the actual PowerShell script. Usually, on Linux, I just use Bash’s eval whenever I need to run something enclosed in a string, because zx will automatically quote and escape everything you’ve passed in through a variable. There’s no eval with PowerShell, so I do an insane amount of googling. At this point, I send him a total of twelve diffs just to test to see what the heck is going on. We eventually settled on using Deno.Command instead of zx for this one, running pwsh C:\\path\\to\\script C:\\path\\to\\image . Later, after I logged off for the night (at 2:00! I thought I’d be in bed by 22:00!), I did realize one thing—while we were installing Deno, I saw that they had an install script irm https://deno.land/install.ps1 | iex . I figured a much, much easier way would’ve been to just run 'C\\path\\to\\script' | iex instead, but my brain at that insane hour was not having it. That’s the whole Windows saga, for now. I still have to adjust the lightness curves a little bit, but other than that, we should be nearing completion. Today, I want to test the script with my macOS friend… provided she wakes up earlier than 21:00. Almost there!"}, {"post_id": 13833, "ts": "2026-06-22T17:45:38Z", "hours": 0.9606, "text": "There I was, scrolling through my Discord servers, when I saw this link: https://www.keithcirkel.co.uk/whats-my-jnd/ It was a small program to calculate the Just Noticeable Difference between two colours, or the JND. Reading the blogpost linked, it mentioned an algorithm called the “CIEDE2000.” And that’s when it hit me—the CIE is a real organization. Of course they would have a formula to calculate the similarities between two colours. That meant that I didn’t have to iterate through my array of wallpaper colours and do simple less-than checks— using CIEDE2000 would be much more accurate . Thankfully, there’s an npm library for this: color-diff. (I was NOT about to implement all that myself.) I also added a bit of randomization to the algorithm, so that should ensure you’re not getting the same wallpaper all the time if you live somewhere where there’s consistent weather patterns. All in all, this probably constitutes a reship, doesn’t it? I’ll probably be tweaking the algorithm slightly as I continue to use it, so stay tuned…"}, {"post_id": 13403, "ts": "2026-06-21T22:58:07Z", "hours": 2.0586, "text": "Wrote a README, and my very first PKGBUILD! Arch Linux is pretty cool :)"}, {"post_id": 13269, "ts": "2026-06-21T18:43:40Z", "hours": 2.2925, "text": "Dumping all the sun data times to ensure the algorithm’s as accurate as possible! (-0.833 is the angle of the sun at sunrise/sunset.)"}, {"post_id": 12898, "ts": "2026-06-21T03:52:27Z", "hours": 2.8158, "text": "Done!!! YEAH! I had to reimplement the output so that it wouldn’t sort into categories, as that turned out to be harder for the final algorithm to find a matching wallpaper. Currently hueRange is unimplemented as I’m not super sure how to go about it, and I’ve got to clean up the easing function code somehow, but other than that, this should be pretty much ready to ship!"}, {"post_id": 12827, "ts": "2026-06-21T00:19:10Z", "hours": 4.1394, "text": "Been formatting this into a full Deno project from an isolated zx idea. Never done anything config-related before, so making something to read/write the config was pretty cool. A lot of writing the analysis code was processing the bash output into something manipulate-able with TypeScript. That was annoying as shit—splitting, filtering, mapping… I never want to process text again in my entire life. Something really unexpected had to be the floating point errors I found in the loop. I was thinking there had to be a better way to populate the better array in the first place, but there didn’t seem to be, so there I was doing let i = 0, i < 1, i += 0.1 and fighting for my life against 0.60000001 . I eventually got so tired of it I just made it a percentage out of 100% instead. Surely this won’t bite me in the back later :) We’ve got cloud cover, shortwave radiation, and sun altitude with the help of Open-Meteo and suncalc. They’re going to map to parameters chroma, lightness, and hue respectively! This’ll be fun…."}]...
|
Title: rainwall by @angelcube | Stardance
Devlogs Title: rainwall by @angelcube | Stardance
Devlogs:
Been formatting this into a full Deno project from an isolated zx idea. Never done anything config-related before, so making something to read/write the config was pretty cool. A lot of writing the analysis code was processing the bash output into something manipulate-able with TypeScript. That was annoying as shit—splitting, filtering, mapping… I never want to process text again in my entire life. Something really unexpected had to be the floating point errors I found in the loop. I was thinking there had to be a better way to populate the better array in the first place, but there didn’t seem to be, so there I was doing let i = 0, i < 1, i += 0.1 and fighting for my life against 0.60000001 . I eventually got so tired of it I just made it a percentage out of 100% instead. Surely this won’t bite me in the back later :) We’ve got cloud cover, shortwave radiation, and sun altitude with the help of Open-Meteo and suncalc. They’re going to map to parameters chroma, lightness, and hue respectively! This’ll be fun….
Done!!! YEAH! I had to reimplement the output so that it wouldn’t sort into categories, as that turned out to be harder for the final algorithm to find a matching wallpaper. Currently hueRange is unimplemented as I’m not super sure how to go about it, and I’ve got to clean up the easing function code somehow, but other than that, this should be pretty much ready to ship!
Dumping all the sun data times to ensure the algorithm’s as accurate as possible! (-0.833 is the angle of the sun at sunrise/sunset.)
Wrote a README, and my very first PKGBUILD! Arch Linux is pretty cool :)
There I was, scrolling through my Discord servers, when I saw this link: https://www.keithcirkel.co.uk/whats-my-jnd/ It was a small program to calculate the Just Noticeable Difference between two colours, or the JND. Reading the blogpost linked, it mentioned an algorithm called the “CIEDE2000.” And that’s when it hit me—the CIE is a real organization. Of course they would have a formula to calculate the similarities between two colours. That meant that I didn’t have to iterate through my array of wallpaper colours and do simple less-than checks— using CIEDE2000 would be much more accurate . Thankfully, there’s an npm library for this: color-diff. (I was NOT about to implement all that myself.) I also added a bit of randomization to the algorithm, so that should ensure you’re not getting the same wallpaper all the time if you live somewhere where there’s consistent weather patterns. All in all, this probably constitutes a reship, doesn’t it? I’ll probably be tweaking the algorithm slightly as I continue to use it, so stay tuned…
I just spent four hours doing genuinely the most annoying thing on the planet: building for Windows . I found a neat little Stack Overflow thread that seemed to do what I wanted it to: write a PowerShell script that could set the wallpaper on Windows machines. Not too shabby, I thought. I could probably ask one of my friends to test on their machine. It wouldn’t take too long, maybe half an hour at max. Boy, was I wrong. I forced the poor bloke to install ImageMagick, then sent him a CI build. We gave the program a test run, and I ran into my first real challenge: paths. Oh my God, I hate Windows paths. Nothing would work—making folders, writing files, any of that until I replaced every single forward slash with Deno’s fromFileUrl . And being a person with not so great memory, I sent over at least five builds before I fixed every single path in the way. Honourable mentions include: I mistook configPath for cachePath fromFileUrl("C:/..") because that is definitely a file:/// URL path.join(`${imageDir}, ${image.name}`) Part 2: PowerShell. I thought ( ) that zx would run on PowerShell out of the box. Nope! It depends (and it actually says this in the README too) that it depends almost exclusively on Bash and Bash escaping. There’s a usePowerShell() command, but I genuinely don’t have the energy right now to figure out the refactors required to make that work—on someone else’s machine . So I make the guy install Git Bash, and also Deno so I can just send him diffs instead of having to send the Full Deno Runtime™ every time I had a new build. At this point, rainwall-analyze finally works (yay!) and dumps the correct paths to the cache folder. We run rainwall-apply , I find four new cases of paths I did not fix, and I go back into VSCode hell. Part 3: the actual PowerShell script. Usually, on Linux, I just use Bash’s eval whenever I need to run something enclosed in a string, because zx will automatically quote and escape everything you’ve passed in through a variable. There’s no eval with PowerShell, so I do an insane amount of googling. At this point, I send him a total of twelve diffs just to test to see what the heck is going on. We eventually settled on using Deno.Command instead of zx for this one, running pwsh C:\path\to\script C:\path\to\image . Later, after I logged off for the night (at 2:00! I thought I’d be in bed by 22:00!), I did realize one thing—while we were installing Deno, I saw that they had an install script irm https://deno.land/install.ps1 | iex . I figured a much, much easier way would’ve been to just run 'C\path\to\script' | iex instead, but my brain at that insane hour was not having it. That’s the whole Windows saga, for now. I still have to adjust the lightness curves a little bit, but other than that, we should be nearing completion. Today, I want to test the script with my macOS friend… provided she wakes up earlier than 21:00. Almost there!
Today I learned that the CIEDE2000 algorithm never worked in the first place and was outputting numbers opposite to on the colour wheel. Why? I have no clue and I don’t intend to find out, because I’ve decided I’ve had enough of typing in sine and cosine and was just going to use the library colordx instead. The whole project was refactored, including the analyze API, so if you’ve had an index file generated previously make sure to regenerate it!
DEVS OF STARDANCE, I need YOUR HELP! Setting wallpapers for multiple monitors on macOS is tediously hard! There’s gotta be a Swift application in the middle accepting this call, so… Would you rather: a Swift library bundled within the (TypeScript) application to interact with Cocoa and handle setting the wallpaper a dependency on another CLI tool like desktoppr for this? LET ME KNOW IN THE COMMENTS! Or something. I’m not a YouTuber
Ships:
🌈 rainwall is done! This is a CLI utility that uses the weather outside to select a matching image as your wallpaper. This was my first time using Deno, and I feel like it’s got its pros and cons. I learned so much in manipulating the actual OS through TypeScript, and I feel much more confiident in it as a scripting language now! I wasn’t able to test on any other architectures, so please submit feedback as needed! You can download rainwall via JSR , GitHub , or with the PKGBUILD !...
|
1793094919.239656
|
1793181319.239656
|
|
29825
|
rain's website by @yagmur | Stardance
|
yagmur
|
1
|
4.42
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-02T13:09:24Z", "hours": 2.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "well this was quick, i’m already well acquainted with html and css so this was just a 3 hour project. feedback don’t need to be long, as i get more active here this will be filled up :) it’s ok if you vote low on technicality and storytelling i borrowed the font from ios (or macos idk) and got a sick wallpaper from unsplash. if you ask about the sections, they’re about me (main content), projects (right panel) and social(s) (badges at the bottom) i only have a github under this alias that’s why it is the only thing listed down there.", "repo": "https://github.com/yagmurpog/yagmurpog.github.io", "demo": "https://yagmurpog.github.io/"}]...
|
[{"post_id": 25975, "ts": "202 [{"post_id": 25975, "ts": "2026-07-10T14:51:49Z", "hours": 2.4208, "text": "new sick css"}, {"post_id": 20736, "ts": "2026-07-02T12:58:27Z", "hours": 1.6558, "text": "i’ll be honest, this is just an one and done quickie, in the past i’ve made many personal websites and this was just one of them. also as i don’t like js i didn’t use it :p"}]...
|
Title: rain's website by @yagmur | Stardance
Title: rain's website by @yagmur | Stardance
Devlogs:
i’ll be honest, this is just an one and done quickie, in the past i’ve made many personal websites and this was just one of them. also as i don’t like js i didn’t use it :p
new sick css
Ships:
well this was quick, i’m already well acquainted with html and css so this was just a 3 hour project. feedback don’t need to be long, as i get more active here this will be filled up :) it’s ok if you vote low on technicality and storytelling i borrowed the font from ios (or macos idk) and got a sick wallpaper from unsplash. if you ask about the sections, they’re about me (main content), projects (right panel) and social(s) (badges at the bottom) i only have a github under this alias that’s why it is the only thing listed down there....
|
1793109269.4388826
|
1793195669.4388826
|
|
2288
|
rail by @codewithjoshh | Stardance
|
codewithjoshh
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: rail by @codewithjoshh | Stardance
|
1792619436.1425154
|
1793224236.1425154
|
|
27206
|
rag feed reader by @keyboardspam | Stardance
|
keyboardspam
|
1
|
28.18
|
96
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-29T20:35:41Z", "hours": 11.0, "multiplier": 17.45, "payout": 96, "blessing": "neutral", "text": "This project is a feed reader for emacs that focuses on performance. The feed reader that I used before this is elfeed so I will be comparing this with that. QOL Improvements (over elfeed) Memory usage The elfeed implementation does a bunch of things that hog memory. For one, the database is held entirely in memory. Rag uses a sqlite database to consume less memory. Another thing is that the xml data is parsed into an AST before it gets processed by the parsers which means that you have both the original XML text and an AST which is duplicated work. To fix this, in rag it uses a xml streaming library (quick-xml) to process xml without an AST. Performance The biggest focus of this is in performance. One of the things that is improved over elfeed is that the elfeed buffer gets redrawn after every update by erasing the buffer and then redrawing everything which is very inefficient. This consumes a lot of time when elfeed finishes parsing feeds now that the updates are incremental and lazy, we are already multitudes faster than elfeed. There are more optimizations such as that are implemented using arena allocators to reuse allocations, or using references to avoid copying data. The reason that I need my feed reader (or anything else I use in Emacs) to be very fast because on Linux (I use an Arch derivative btw) I use EXWM as my window manager so whenever ELISP code blocks, I cannot use my computer to do anything else (like remembering to use Emacs as a text editor). As a result I want my feed reader to be as fast as possible. Reliability One of the issues that I have with elfeed is a bug (that I haven’t reported because idk how to describe or reproduce, I also don’t have any screenshots) where after the elfeed database gets large enough with entries, the description of entries ends up incorrect where it cuts off halfway or it shows you the description of the wrong entry. I suspect that this has something to do with the fact that the database they use is a custom one implemented in ELISP (before Emacs got sqlite support) so by making a feed reader that uses sqlite which is very battle tested, in my limited experience so far, the database is more reliable here than in elfeed.", "repo": "https://github.com/butterfingres/rag", "demo": "https://github.com/butterfingres/rag/releases"}]...
|
[{"post_id": 32579, "ts": "202 [{"post_id": 32579, "ts": "2026-07-21T21:00:54Z", "hours": 1.1211, "text": "After figuring out how to use cargo build with makefiles to test elisp dynamic modules, and replacing it in my other project, I replaced the build system from a configure script + makefiles to makefiles + cargo to run tests."}, {"post_id": 31389, "ts": "2026-07-19T18:33:09Z", "hours": 5.6822, "text": "I made parsing happen inside of a thread pool in order to have parallelism to not block the main thread. Everything now happens much faster and is more responsive now."}, {"post_id": 24640, "ts": "2026-07-08T11:18:13Z", "hours": 3.5075, "text": "I added handling ttl caches to prevent spamming rss feeds and added building shared libraries for musl libc users on linux."}, {"post_id": 21456, "ts": "2026-07-03T12:41:45Z", "hours": 3.0242, "text": "The dublin core, syndication, content and media namespace parsers are now complete and all feed types are able to support them. Now you view feeds that don’t use most of their native elements."}, {"post_id": 19954, "ts": "2026-07-01T12:26:25Z", "hours": 3.8461, "text": "I added support for the Dublin Core (dc) and Media RSS (media) namespaces in feeds. My favorite part of this was handling date and time because it is always just so fun. In Dublin Core, not only do the specs say that you can have incomplete ISO-8601 timestamps like (2000), (2000-01) but you could also specify time ranges like (2000/2000-02-01) https://www.dublincore.org/specifications/dublin-core/dcmi-terms/#date meaning the publishing date is somewhere between 2000-01-01 and 2000-02-01 leading to this amazing function. The best part of all this is that there is going to be more complicated date time handling when I write the syndication (sy) namespace handler."}, {"post_id": 18609, "ts": "2026-06-29T20:10:01Z", "hours": 1.2136, "text": "I wrote a README that describes the project and its goals that doubles for my ship description."}, {"post_id": 18540, "ts": "2026-06-29T18:38:25Z", "hours": 2.3694, "text": "I added a github actions workflow that builds release artifacts for windows, mac, and linux in x86_64 and aarch64 + a bunch of obscure linux architectures. I also added a installation guide at https://github.com/butterfingres/rag/blob/master/README.org so now I can finally ship this."}, {"post_id": 18407, "ts": "2026-06-29T15:22:33Z", "hours": 4.0789, "text": "The entries that are parsed from the feeds now get inserted into the buffer using binary search to incrementally you new entries. All that would be left is to create a guide for non-Emacs users so that people can tests it and also CI builds for releases for a bunch of different architectures then I could ship."}, {"post_id": 18010, "ts": "2026-06-28T23:45:38Z", "hours": 1.32, "text": "I added an entry viewer so now you can look see the description of feeds. The ui is “inspired” by elfeed. The only thing left before shipping would be a configuration interface for feeds to add your rss feeds followed by a scheduler for downloading them."}, {"post_id": 17807, "ts": "2026-06-28T18:59:14Z", "hours": 0.6406, "text": "Made the feed reader put the parsed entries & feeds into a sqlite database. I also added a basic frontend to the database that currently only shows feed titles."}, {"post_id": 17258, "ts": "2026-06-27T23:41:21Z", "hours": 1.3494, "text": "finished parsing all the feed xml formats (rss, rdf, atom) will start working on the front-end soon. there’s not much to show bc its backend stuff."}]...
|
Title: rag feed reader by @keyboardspam | Stardanc Title: rag feed reader by @keyboardspam | Stardance
Devlogs:
finished parsing all the feed xml formats (rss, rdf, atom) will start working on the front-end soon. there’s not much to show bc its backend stuff.
Made the feed reader put the parsed entries & feeds into a sqlite database. I also added a basic frontend to the database that currently only shows feed titles.
I added an entry viewer so now you can look see the description of feeds. The ui is “inspired” by elfeed. The only thing left before shipping would be a configuration interface for feeds to add your rss feeds followed by a scheduler for downloading them.
The entries that are parsed from the feeds now get inserted into the buffer using binary search to incrementally you new entries. All that would be left is to create a guide for non-Emacs users so that people can tests it and also CI builds for releases for a bunch of different architectures then I could ship.
I added a github actions workflow that builds release artifacts for windows, mac, and linux in x86_64 and aarch64 + a bunch of obscure linux architectures. I also added a installation guide at https://github.com/butterfingres/rag/blob/master/README.org so now I can finally ship this.
I wrote a README that describes the project and its goals that doubles for my ship description.
I added support for the Dublin Core (dc) and Media RSS (media) namespaces in feeds. My favorite part of this was handling date and time because it is always just so fun. In Dublin Core, not only do the specs say that you can have incomplete ISO-8601 timestamps like (2000), (2000-01) but you could also specify time ranges like (2000/2000-02-01) https://www.dublincore.org/specifications/dublin-core/dcmi-terms/#date meaning the publishing date is somewhere between 2000-01-01 and 2000-02-01 leading to this amazing function. The best part of all this is that there is going to be more complicated date time handling when I write the syndication (sy) namespace handler.
The dublin core, syndication, content and media namespace parsers are now complete and all feed types are able to support them. Now you view feeds that don’t use most of their native elements.
I added handling ttl caches to prevent spamming rss feeds and added building shared libraries for musl libc users on linux.
I made parsing happen inside of a thread pool in order to have parallelism to not block the main thread. Everything now happens much faster and is more responsive now.
After figuring out how to use cargo build with makefiles to test elisp dynamic modules, and replacing it in my other project, I replaced the build system from a configure script + makefiles to makefiles + cargo to run tests.
Ships:
This project is a feed reader for emacs that focuses on performance. The feed reader that I used before this is elfeed so I will be comparing this with that. QOL Improvements (over elfeed) Memory usage The elfeed implementation does a bunch of things that hog memory. For one, the database is held entirely in memory. Rag uses a sqlite database to consume less memory. Another thing is that the xml data is parsed into an AST before it gets processed by the parsers which means that you have both the original XML text and an AST which is duplicated work. To fix this, in rag it uses a xml streaming library (quick-xml) to process xml without an AST. Performance The biggest focus of this is in performance. One of the things that is improved over elfeed is that the elfeed buffer gets redrawn after every update by erasing the buffer and then redrawing everything which is very inefficient. This consumes a lot of time when elfeed finishes parsing feeds now that the updates are incremental and lazy, we are already multitudes faster than elfeed. There are more optimizations such as that are implemented using arena allocators to reuse allocations, or using references to avoid copying data. The reason that I need my feed reader (or anything else I use in Emacs) to be very fast because on Linux (I use an Arch derivative btw) I use EXWM as my window manager so whenever ELISP code blocks, I cannot use my computer to do anything else (like remembering to use Emacs as a text editor). As a result I want my feed reader to be as fast as possible. Reliability One of the issues that I have with elfeed is a bug (that I haven’t reported because idk how to describe or reproduce, I also don’t have any screenshots) where after the elfeed database gets large enough with entries, the description of entries ends up incorrect where it cuts off halfway or it shows you the description of the wrong entry. I suspect that this has something to do with the fact that the database they use is a custom one implemented in ELISP (before Emacs got sqlite support) so by making a feed reader that uses sqlite which is very battle tested, in my limited experience so far, the database is more reliable here than in elfeed....
|
1793109053.7076657
|
1793195453.7076657
|
|
4334
|
raft by @pinyuan | Stardance
|
pinyuan
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: raft by @pinyuan | Stardance
|
1792615645.992323
|
1793220445.992323
|
|
4598
|
rafBook by @raf | Stardance
|
raf
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: rafBook by @raf | Stardance
|
1792658874.4293325
|
1793263674.4293325
|
|
60330
|
rae by @sylvieisnton | Stardance
|
sylvieisnton
|
0
|
2.62
|
0
|
[]
|
[{"post_id": 68096, "ts": "202 [{"post_id": 68096, "ts": "2026-09-14T14:39:39Z", "hours": 2.6247, "text": "full parser, tests"}]...
|
Title: rae by @sylvieisnton | Stardance
Devlogs:
Title: rae by @sylvieisnton | Stardance
Devlogs:
full parser, tests...
|
1793033415.6106722
|
1793638215.6106722
|
|
45440
|
radio by @TiredTiddles | Stardance
|
TiredTiddles
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: radio by @TiredTiddles | Stardance
|
1792623255.7112172
|
1793228055.7112172
|
|
57721
|
radio box by @Nolan-L-from-Milorad | Stardance
|
Nolan-L-from-Milorad
|
0
|
5.6
|
0
|
[]
|
[{"post_id": 67089, "ts": "202 [{"post_id": 67089, "ts": "2026-09-13T04:28:12Z", "hours": 0.55, "text": "I forgot to record myself assembling the case out of excitement, so I lost like 3 stardust there :(. aside from that the case looks great! 📻 💣 Modelling the curve was fairly simple, just a spline cutting off the top of the case and a bunch of minor cleanup for the random little bits I missed"}, {"post_id": 66995, "ts": "2026-09-13T00:33:55Z", "hours": 1.85, "text": "I’ve locked in with 3d modeling and learned how amazing flatbed scanners are for creating scaled reference for 3d modeling, I’ve made a super well fitting case in quite a short amount of time! Photos included below, next I need to make the case smooth and curvy to better fit the user’s hand."}, {"post_id": 66158, "ts": "2026-09-11T20:01:53Z", "hours": 2.3636, "text": "Big things! I have two working usb rechargeable radios my friend saw the duct tape one and wanted his rechargeable too! (with a proper case), Next I’m going to write a mod guide, as I have been taking pictures of the process and make some cases! The battery circuit is super simple, It’s just an 18650, a charger board and a fuse (ask why I am now using a fuse) the whole mod is less than $10"}, {"post_id": 61956, "ts": "2026-09-05T04:24:15Z", "hours": 0.8333, "text": "So my friend gave me a bare circuit board for a premium nextech 0.5 UHF walkie talkie. I’m going to make a 3d printed case with space for a lithium battery that fits a nextech radio’s curcuit board, because we all know that cheap radio with smash the microsecond you drop it. So far I have built a Shrek Pod of a radio using stuff I had."}]...
|
Title: radio box by @Nolan-L-from-Milorad | Starda Title: radio box by @Nolan-L-from-Milorad | Stardance
Devlogs:
So my friend gave me a bare circuit board for a premium nextech 0.5 UHF walkie talkie. I’m going to make a 3d printed case with space for a lithium battery that fits a nextech radio’s curcuit board, because we all know that cheap radio with smash the microsecond you drop it. So far I have built a Shrek Pod of a radio using stuff I had.
Big things! I have two working usb rechargeable radios my friend saw the duct tape one and wanted his rechargeable too! (with a proper case), Next I’m going to write a mod guide, as I have been taking pictures of the process and make some cases! The battery circuit is super simple, It’s just an 18650, a charger board and a fuse (ask why I am now using a fuse) the whole mod is less than $10
I’ve locked in with 3d modeling and learned how amazing flatbed scanners are for creating scaled reference for 3d modeling, I’ve made a super well fitting case in quite a short amount of time! Photos included below, next I need to make the case smooth and curvy to better fit the user’s hand.
I forgot to record myself assembling the case out of excitement, so I lost like 3 stardust there :(. aside from that the case looks great! 📻 💣 Modelling the curve was fairly simple, just a spline cutting off the top of the case and a bunch of minor cleanup for the random little bits I missed...
|
1792716896.7644303
|
1793321696.7644303
|
|
67020
|
radiante by @ardente_c | Stardance
|
ardente_c
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: radiante by @ardente_c | Stardance
|
1793105554.9412928
|
1793710354.9412928
|
|
70928
|
radiant os by @Elia_Piagentini | Stardance
|
Elia_Piagentini
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: radiant os by @Elia_Piagentini | Stardance
|
1792680449.4495711
|
1793285249.4495711
|
|
32201
|
radar scanner by @koceris | Stardance
|
koceris
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: radar scanner by @koceris | Stardance
|
1792745467.6038032
|
1793350267.6038032
|
|
35233
|
rad apple by @immaturegoat | Stardance
|
immaturegoat
|
0
|
1.79
|
0
|
[]
|
[{"post_id": 35275, "ts": "202 [{"post_id": 35275, "ts": "2026-07-26T16:09:04Z", "hours": 1.7853, "text": "probably gonna be the only devlog I made bad apple run in terminal using the cascii rust crate to convert the video to frames, and then drew those frames while clearing the terminal. This is just a joke project so I’m not gonna ship it or anything. Here’s the code, but it’s pretty bad. I’m by no means the greatest programmer. There’s also a lot of warnings, but I’m too lazy to fix them. use cascii::{AsciiConverter, VideoOptions, ConversionOptions}; use std::path: :Path; use std::fs::{self, File}; use std::io::Read; use terminal_size::{Width, Height, terminal_size}; use crossterm::{ cursor::{Hide, Show, MoveTo}, execute, terminal::{Clear, ClearType}, }; use std::io::{self, stdout}; use std::thread; use std::time::Duration; fn main() -> std::io::Result<()> { if !Path::new(\"output_frames\").is_dir() { get_frames(); } let mut frames: Vec<String> = read_files()?; play_animation(frames)?; // println!(\"{}\", frames[0]); Ok(()) } fn get_frames() -> Result<(), Box<dyn std::error: :Error>> { let converter = AsciiConverter::new(); let size = terminal_size(); let mut width: u32 = 80; let mut height = 0; if let Some((Width(w), Height(h))) = size { width = u32::from(w); } else { println!(\"unable to get terminal size\"); } let video_options = VideoOptions { fps: 30, start: Some(\"0\".to_string()), end: Some(\"10\".to_string()), columns: width, extract_audio: false, preprocess_filter: None, }; let conversion_options = ConversionOptions::default().with_font_ratio(0.2).with_luminance(20).with_columns(width); converter.convert_video(Path::new(\"assets/apple.mp4\"), Path::new(\"output_frames\"), &video_options, &conversion_options, false)?; Ok(()) } fn read_files() -> std::io::Result<Vec<String>> { let mut files = Vec::new(); for file in fs::read_dir(\"output_frames/\").unwrap() { files.push(file.unwrap().path().display().to_string()); } files.sort(); let mut frames: Vec<String> = Vec::new(); for file in files { let content = fs::read_to_string(file); let frame = match content { Ok(val) => val, Err(err) => format!(\"error: {}\", err), }; frames.push(frame); } Ok(frames) } fn play_animation(frames: Vec<String>) -> io::Result<()> { let frame = 0; let mut stdout = stdout(); for frame in &frames { execute!(stdout, Hide, Clear(ClearType::All))?; execute!(stdout, MoveTo(0, 0)); println!(\"{}\", frame); thread::sleep(Duration::from_millis(33)); } execute!(stdout, Show)?; Ok(()) }"}]...
|
Title: rad apple by @immaturegoat | Stardance
Dev Title: rad apple by @immaturegoat | Stardance
Devlogs:
probably gonna be the only devlog I made bad apple run in terminal using the cascii rust crate to convert the video to frames, and then drew those frames while clearing the terminal. This is just a joke project so I’m not gonna ship it or anything. Here’s the code, but it’s pretty bad. I’m by no means the greatest programmer. There’s also a lot of warnings, but I’m too lazy to fix them. use cascii::{AsciiConverter, VideoOptions, ConversionOptions}; use std::path: :Path; use std::fs::{self, File}; use std::io::Read; use terminal_size::{Width, Height, terminal_size}; use crossterm::{ cursor::{Hide, Show, MoveTo}, execute, terminal::{Clear, ClearType}, }; use std::io::{self, stdout}; use std::thread; use std::time::Duration; fn main() -> std::io::Result<()> { if !Path::new("output_frames").is_dir() { get_frames(); } let mut frames: Vec<String> = read_files()?; play_animation(frames)?; // println!("{}", frames[0]); Ok(()) } fn get_frames() -> Result<(), Box<dyn std::error: :Error>> { let converter = AsciiConverter::new(); let size = terminal_size(); let mut width: u32 = 80; let mut height = 0; if let Some((Width(w), Height(h))) = size { width = u32::from(w); } else { println!("unable to get terminal size"); } let video_options = VideoOptions { fps: 30, start: Some("0".to_string()), end: Some("10".to_string()), columns: width, extract_audio: false, preprocess_filter: None, }; let conversion_options = ConversionOptions::default().with_font_ratio(0.2).with_luminance(20).with_columns(width); converter.convert_video(Path::new("assets/apple.mp4"), Path::new("output_frames"), &video_options, &conversion_options, false)?; Ok(()) } fn read_files() -> std::io::Result<Vec<String>> { let mut files = Vec::new(); for file in fs::read_dir("output_frames/").unwrap() { files.push(file.unwrap().path().display().to_string()); } files.sort(); let mut frames: Vec<String> = Vec::new(); for file in files { let content = fs::read_to_string(file); let frame = match content { Ok(val) => val, Err(err) => format!("error: {}", err), }; frames.push(frame); } Ok(frames) } fn play_animation(frames: Vec<String>) -> io::Result<()> { let frame = 0; let mut stdout = stdout(); for frame in &frames { execute!(stdout, Hide, Clear(ClearType::All))?; execute!(stdout, MoveTo(0, 0)); println!("{}", frame); thread::sleep(Duration::from_millis(33)); } execute!(stdout, Show)?; Ok(()) }...
|
1792767168.1740627
|
1793371968.1740627
|
|
44359
|
racing_speed game by @saanvi-singh | Stardance
|
saanvi-singh
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: racing_speed game by @saanvi-singh | Starda Title: racing_speed game by @saanvi-singh | Stardance...
|
1792583495.9841259
|
1793188295.9841259
|
|
4878
|
racing sim track from scratch by @dk | Stardance
|
dk
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: racing sim track from scratch by @dk | Star Title: racing sim track from scratch by @dk | Stardance...
|
1792554534.5764744
|
1793159334.5764744
|
|
47987
|
racing dd wheel by @PHELIX | Stardance
|
PHELIX
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: racing dd wheel by @PHELIX | Stardance
|
1792536562.19377
|
1793141362.19377
|
|
1862
|
racing controller by @Notsteven | Stardance
|
Notsteven
|
1
|
1.97
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-05T22:55:39Z", "hours": 0.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "My project is a racing/ driving gamepad that you can use on the go or at home. One of the most challenging parts of this project was deciding what to add in the beginning stages and what the main parts were to focus on to make it functional. One thing you should know is that, currently, my project is just a 3d model. I am waiting for the hardware fund to open so i can request the things I need. The demo link leads you to the Onshape where I’ve done most of the work. This lets you view the current model more in-depth", "repo": "https://github.com/tottallynotstevenp/steering-wheel-controller", "demo": ""}]...
|
[{"post_id": 34895, "ts": "202 [{"post_id": 34895, "ts": "2026-07-25T23:58:58Z", "hours": 1.5631, "text": "7/25 update ive made the breadboard test and have made the code. in the following days i plan to add the holes or places for the components to fit in the actual controller body"}, {"post_id": 7855, "ts": "2026-06-13T03:08:51Z", "hours": 0.4108, "text": "i changed the top plate to make the assembly eassier and also moved somethings around so the extrude would be much better"}, {"post_id": 2982, "ts": "2026-06-05T22:15:58Z", "hours": 0.6658, "text": "added the sliders for the linear potentiometers for the gas and brake. ive also realised i havent really explaied how it all works so heres how it works The main steering component is a rotary encoder with a push button. This will send analog input to the ESP32, which will then send that input to the device it’s connected to. The shifting and turn signal controls are just simple buttons, which will also go to the ESP32. The gas and brake pedals are linear potentiometers with a travel of 20mm. This will allow you to control the speed of acceleration and braking as if you were using actual brake and gas pedals."}, {"post_id": 2573, "ts": "2026-06-05T04:31:35Z", "hours": 2.1989, "text": "Changes made I made a couple of changes, including moving the turn signals to right above the gear shifting. Another change i made is changing the steering wheel design from a realistic-looking one to a more ergonomic one for longer sessions. I’ve also made a lot of cosmetic changes, including adding arrows to signify what each button does and adding a hazards button in addition to the turn signal buttons. Near future Currently trying to figure out what would be better, a mix of two linear potentiometers for gas and brake, or a pair of triggers for the gas and brake. More than likely will go with the linear potentiometers because it gives you that sense of more control than triggers could give you. I am also trying to find more things i could add to make using the controller more of an experience"}, {"post_id": 1214, "ts": "2026-06-03T02:13:56Z", "hours": 1.2972, "text": "Hey my name is Steven, and I really like playing driving games, so I decided to create a steering-wheel controller you can use on the go. This is a really rough design I have started working on. The final version will include some extra buttons that you will be able to map to anything you want to"}]...
|
Title: racing controller by @Notsteven | Stardance Title: racing controller by @Notsteven | Stardance
Devlogs:
Hey my name is Steven, and I really like playing driving games, so I decided to create a steering-wheel controller you can use on the go. This is a really rough design I have started working on. The final version will include some extra buttons that you will be able to map to anything you want to
Changes made I made a couple of changes, including moving the turn signals to right above the gear shifting. Another change i made is changing the steering wheel design from a realistic-looking one to a more ergonomic one for longer sessions. I’ve also made a lot of cosmetic changes, including adding arrows to signify what each button does and adding a hazards button in addition to the turn signal buttons. Near future Currently trying to figure out what would be better, a mix of two linear potentiometers for gas and brake, or a pair of triggers for the gas and brake. More than likely will go with the linear potentiometers because it gives you that sense of more control than triggers could give you. I am also trying to find more things i could add to make using the controller more of an experience
added the sliders for the linear potentiometers for the gas and brake. ive also realised i havent really explaied how it all works so heres how it works The main steering component is a rotary encoder with a push button. This will send analog input to the ESP32, which will then send that input to the device it’s connected to. The shifting and turn signal controls are just simple buttons, which will also go to the ESP32. The gas and brake pedals are linear potentiometers with a travel of 20mm. This will allow you to control the speed of acceleration and braking as if you were using actual brake and gas pedals.
i changed the top plate to make the assembly eassier and also moved somethings around so the extrude would be much better
7/25 update ive made the breadboard test and have made the code. in the following days i plan to add the holes or places for the components to fit in the actual controller body
Ships:
My project is a racing/ driving gamepad that you can use on the go or at home. One of the most challenging parts of this project was deciding what to add in the beginning stages and what the main parts were to focus on to make it functional. One thing you should know is that, currently, my project is just a 3d model. I am waiting for the hardware fund to open so i can request the things I need. The demo link leads you to the Onshape where I’ve done most of the work. This lets you view the current model more in-depth...
|
1793134380.6094737
|
1793220780.6094737
|
|
32733
|
racers clash by @mizuprobrawl | Stardance
|
mizuprobrawl
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: racers clash by @mizuprobrawl | Stardance
|
1792597895.367239
|
1793202695.367239
|
|
7439
|
race to the summit by @alyah | Stardance
|
alyah
|
1
|
10.93
|
35
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-14T16:17:11Z", "hours": 10.0, "multiplier": 3.35, "payout": 35, "blessing": "neutral", "text": "I made a racing game in Pygame from scratch by myself of a car driving simulator through three different mountain season regions. This project took way longer than it should’ve but I’ve learned so much about functions, math, and debugging.", "repo": "https://github.com/lyri3aly/race-to-the-summit", "demo": "https://lyri3aly.github.io/race-to-the-summit/"}]...
|
[{"post_id": 17168, "ts": "202 [{"post_id": 17168, "ts": "2026-06-27T21:26:25Z", "hours": 0.2956, "text": "finally got the pygbag folders working! race to the summit has a working github page now. playable here: https://lyri3aly.github.io/race-to-the-summit/"}, {"post_id": 12570, "ts": "2026-06-20T15:04:38Z", "hours": 0.6381, "text": "for the person reviewing my ship: pygbag and anything else literally isn’t running for some reason and I am unable to push my pygame file to the web, so it’s just going to be the github .py file"}, {"post_id": 8764, "ts": "2026-06-14T16:00:55Z", "hours": 2.7431, "text": "Final tasks! timer is now completed (stopwatch of time it takes for the user to drive to the summit) car designs. car can now be blue, yellow, or white commented everything"}, {"post_id": 7220, "ts": "2026-06-12T01:43:42Z", "hours": 2.5333, "text": "race the summit now officially has boundaries and collision detection! this project has taken way longer than it should.. but i’m happy i’m almost finished. here are the key takeways from this edition: the car can’t go pass the road now! it must stay inside or it will rebound and occasionally get “stuck in a ditch” camera tracking works perfectly- no more car disappearing off the screen win screen and help screen reset button (“R”)"}, {"post_id": 5319, "ts": "2026-06-09T01:44:52Z", "hours": 5.1133, "text": "i’m working on a racing game called “race to the summit” in pygame. the objective is, basically, to reach the summit. the game takes you along a long winding path throughout mountains and three different seasons. i’m still working on the artwork so there’s an ai generated placeholder there for now. here are the things I’ve been able to accomplish so far: car physics (acceleration, friction, spinning, turning, etc.), however, I can’t seem to gradually slow down the car spinning in circles alone through friction. friction only applies to the car going straight for some reason?? some camera tracking. when accelerating, the car goes out of frame sometimes… game menu, loading screen, and logo!! imported most images I will be using including the different colours available in “car design” soon"}]...
|
Title: race to the summit by @alyah | Stardance
D Title: race to the summit by @alyah | Stardance
Devlogs:
i’m working on a racing game called “race to the summit” in pygame. the objective is, basically, to reach the summit. the game takes you along a long winding path throughout mountains and three different seasons. i’m still working on the artwork so there’s an ai generated placeholder there for now. here are the things I’ve been able to accomplish so far: car physics (acceleration, friction, spinning, turning, etc.), however, I can’t seem to gradually slow down the car spinning in circles alone through friction. friction only applies to the car going straight for some reason?? some camera tracking. when accelerating, the car goes out of frame sometimes… game menu, loading screen, and logo!! imported most images I will be using including the different colours available in “car design” soon
race the summit now officially has boundaries and collision detection! this project has taken way longer than it should.. but i’m happy i’m almost finished. here are the key takeways from this edition: the car can’t go pass the road now! it must stay inside or it will rebound and occasionally get “stuck in a ditch” camera tracking works perfectly- no more car disappearing off the screen win screen and help screen reset button (“R”)
Final tasks! timer is now completed (stopwatch of time it takes for the user to drive to the summit) car designs. car can now be blue, yellow, or white commented everything
for the person reviewing my ship: pygbag and anything else literally isn’t running for some reason and I am unable to push my pygame file to the web, so it’s just going to be the github .py file
finally got the pygbag folders working! race to the summit has a working github page now. playable here: https://lyri3aly.github.io/race-to-the-summit/
Ships:
I made a racing game in Pygame from scratch by myself of a car driving simulator through three different mountain season regions. This project took way longer than it should’ve but I’ve learned so much about functions, math, and debugging....
|
1793134288.3244936
|
1793220688.3244936
|
|
60880
|
rabbitOS by @kas_kadiia | Stardance
|
kas_kadiia
|
1
|
15.73
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-13T07:47:28Z", "hours": 12.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I created a Rabbit and Steel themed WebOS, following the WebOS-1 tutorial to begin with it. This WebOS features a timer, a music player, an embedded Fandom Wiki link, and settings the OS remembers. Making this with genuinely almost no prior HTML, CSS, and JS experience took some time, but I got the hang of it, even if I feel like some of this is done incredibly inefficiently or could be done better. If anything, the prospect of refactoring later for future expansion is what scares me. In the end, I am still happy with how it turned out, especially with adding some animated images.", "repo": "https://github.com/kaskadiia/rabbit-OS", "demo": "https://kaskadiia.github.io/rabbit-OS/"}]...
|
[{"post_id": 69452, "ts": "202 [{"post_id": 69452, "ts": "2026-09-17T02:37:32Z", "hours": 1.5356, "text": "Devlog #7 I made a simple start-up screen, but I spent an hour fighting image scaling and general dimension quirks until I (mostly) figured it out. I used a simple fade-in from black paired with a fading blur effect to try and recreate the intro to Rabbit and Steel, along with using a cut version of the intro OST. (except I forgot browsers block autoplaying audio)"}, {"post_id": 68958, "ts": "2026-09-16T03:31:13Z", "hours": 2.19, "text": "Devlog #6 Well, now I move onto WebOS 2. I made the windows resizable! It took way too long to figure out why scrolling content wasn’t working, since I wanted it to be able to scroll if a window was really small. But, that was really only one of the problems. After figuring that out, I still needed to readjust the apps and the other content, such as the music room animation or the timer crow. The best option I could think of? Don’t even deal with it (for now). So for the time being, the animations are gone. I also made the app icons animated with basic CSS animations, and I think it just adds a nice touch to it."}, {"post_id": 67064, "ts": "2026-09-13T03:33:49Z", "hours": 2.1717, "text": "Devlog #5 Added a timer app. This took a bit of time to figure out in terms of functionality. But I was far more frustrated with trying to position Twili (the crow) and the rings in the center. Like the music player rabbits, this is animated as well, and the rings rotate. I also added sound effects from Rabbit and Steel for the timer being started and when it goes off, since what good does a timer do if it doesn’t notify you audibly?"}, {"post_id": 66997, "ts": "2026-09-13T00:40:06Z", "hours": 1.825, "text": "Devlog #4 Added a music player. This music player just uses the Spotify preview embed of a playlist containing the full Rabbit and Steel OST, which I thought was preferable than importing all the sound files. It took me some time to figure out how to make the image animated, as it was a spritesheet taken directly from the game, but I think it adds a lot more to the music player. In future apps, I definitely want to add more animated assets. I have also expanded the settings page to include all backgrounds in Rabbit and Steel, and I have utilized local storage to save the settings and the background for future visits."}, {"post_id": 66891, "ts": "2026-09-12T20:48:57Z", "hours": 2.5692, "text": "Devlog #3 Added a settings page, albeit very barebones at the moment. This allows you to change the backgrounds; matching with game area backgrounds in Rabbit and Steel. There are two settings for window blur and drop shadow. I also spent (a lot of) time trying to add transitions but I honestly still have no clue how to use them properly. I’ll add more backgrounds to select later, but I want to make some other app."}, {"post_id": 66352, "ts": "2026-09-12T04:06:51Z", "hours": 2.7928, "text": "Devlog #2 I did some polishing and made a new app. I decided not to make a notes app as the guide directs, because I felt it to be unfitting. So, I instead made an embedded wiki (although I hate Fandom, Miraheze will not load)."}, {"post_id": 66279, "ts": "2026-09-12T00:52:31Z", "hours": 2.3114, "text": "A Rabbit and Steel themed WebOS? You should steel yourself NOW! Rabbit and Steel has been one of my favorite games to play, especially with friends. So I thought, if I were to make a WebOS for Stardance, I wouldn’t try to make one that would be useful in every single sector possible, but something that I would just have fun with. So I landed with a Rabbit and Steel themed idea. Right now, all I’ve made is the landing window, topbar, and a background, loosely based on the white border and dark transparent background used in the Rabbit and Steel UI. Obviously, the next course of action is following through on the guide, but then I will try to add more Rabbit and Steel themed features later. Anyways, you should play Rabbit and Steel."}]...
|
Title: rabbitOS by @kas_kadiia | Stardance
Devlog Title: rabbitOS by @kas_kadiia | Stardance
Devlogs:
A Rabbit and Steel themed WebOS? You should steel yourself NOW! Rabbit and Steel has been one of my favorite games to play, especially with friends. So I thought, if I were to make a WebOS for Stardance, I wouldn’t try to make one that would be useful in every single sector possible, but something that I would just have fun with. So I landed with a Rabbit and Steel themed idea. Right now, all I’ve made is the landing window, topbar, and a background, loosely based on the white border and dark transparent background used in the Rabbit and Steel UI. Obviously, the next course of action is following through on the guide, but then I will try to add more Rabbit and Steel themed features later. Anyways, you should play Rabbit and Steel.
Devlog #2 I did some polishing and made a new app. I decided not to make a notes app as the guide directs, because I felt it to be unfitting. So, I instead made an embedded wiki (although I hate Fandom, Miraheze will not load).
Devlog #3 Added a settings page, albeit very barebones at the moment. This allows you to change the backgrounds; matching with game area backgrounds in Rabbit and Steel. There are two settings for window blur and drop shadow. I also spent (a lot of) time trying to add transitions but I honestly still have no clue how to use them properly. I’ll add more backgrounds to select later, but I want to make some other app.
Devlog #4 Added a music player. This music player just uses the Spotify preview embed of a playlist containing the full Rabbit and Steel OST, which I thought was preferable than importing all the sound files. It took me some time to figure out how to make the image animated, as it was a spritesheet taken directly from the game, but I think it adds a lot more to the music player. In future apps, I definitely want to add more animated assets. I have also expanded the settings page to include all backgrounds in Rabbit and Steel, and I have utilized local storage to save the settings and the background for future visits.
Devlog #5 Added a timer app. This took a bit of time to figure out in terms of functionality. But I was far more frustrated with trying to position Twili (the crow) and the rings in the center. Like the music player rabbits, this is animated as well, and the rings rotate. I also added sound effects from Rabbit and Steel for the timer being started and when it goes off, since what good does a timer do if it doesn’t notify you audibly?
Devlog #6 Well, now I move onto WebOS 2. I made the windows resizable! It took way too long to figure out why scrolling content wasn’t working, since I wanted it to be able to scroll if a window was really small. But, that was really only one of the problems. After figuring that out, I still needed to readjust the apps and the other content, such as the music room animation or the timer crow. The best option I could think of? Don’t even deal with it (for now). So for the time being, the animations are gone. I also made the app icons animated with basic CSS animations, and I think it just adds a nice touch to it.
Devlog #7 I made a simple start-up screen, but I spent an hour fighting image scaling and general dimension quirks until I (mostly) figured it out. I used a simple fade-in from black paired with a fading blur effect to try and recreate the intro to Rabbit and Steel, along with using a cut version of the intro OST. (except I forgot browsers block autoplaying audio)
Ships:
I created a Rabbit and Steel themed WebOS, following the WebOS-1 tutorial to begin with it. This WebOS features a timer, a music player, an embedded Fandom Wiki link, and settings the OS remembers. Making this with genuinely almost no prior HTML, CSS, and JS experience took some time, but I got the hang of it, even if I feel like some of this is done incredibly inefficiently or could be done better. If anything, the prospect of refactoring later for future expansion is what scares me. In the end, I am still happy with how it turned out, especially with adding some animated images....
|
1793055259.1367185
|
1793141659.1367185
|
|
39293
|
ra-bot by @dhruvra | Stardance
|
dhruvra
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: ra-bot by @dhruvra | Stardance
|
1792648051.243759
|
1793252851.243759
|
|
56968
|
r2-quickshell-configs by @nitrogeo | Stardance
|
nitrogeo
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: r2-quickshell-configs by @nitrogeo | Starda Title: r2-quickshell-configs by @nitrogeo | Stardance...
|
1792687732.8702757
|
1793292532.8702757
|
|
13579
|
r u cooked API Project by @birdyboyiyert | Stardan r u cooked API Project by @birdyboyiyert | Stardance...
|
birdyboyiyert
|
0
|
0.0
|
0
|
[]
|
[]
|
Title: r u cooked API Project by @birdyboyiyert | Title: r u cooked API Project by @birdyboyiyert | Stardance...
|
1793184912.3880036
|
1793789712.3880036
|