<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>devin&apos;s blog</title><description>hi, i&apos;m devin! :)</description><link>https://devins.page/</link><item><title>i like Fish</title><link>https://devins.page/blog/fish-and-starship/</link><guid isPermaLink="true">https://devins.page/blog/fish-and-starship/</guid><description>a smart, user-friendly command line shell w/ a really good out-of-box experience</description><pubDate>Tue, 24 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://fishshell.com&quot;&gt;fish&lt;/a&gt; (&lt;strong&gt;f&lt;/strong&gt;riendly &lt;strong&gt;i&lt;/strong&gt;nteractive &lt;strong&gt;sh&lt;/strong&gt;ell) is a &quot;smart and user-friendly command line shell for Linux, macOS, and the rest of the family&quot;. It contains so many useful features built-in, which you usually have to configure to add to other shells, and is overall much easier to work with than others.&lt;/p&gt;
&lt;p&gt;I discovered it from a couple of my friends and it has made using the command line a lot easier and more attractive for me. It&apos;s pretty easy to install and use.&lt;/p&gt;
&lt;h2&gt;features&lt;/h2&gt;
&lt;h3&gt;autosuggestions&lt;/h3&gt;
&lt;p&gt;Start typing any command and fish will try its best to complete the command for you. It also gets auto suggestions from your history. For example, lets say you had a long command that you ran a month ago and you wanna run it again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ git log --au
    fish autocompletes for you based on history
❯ git log --author &quot;intergrav&quot; --since &quot;1 year&quot;
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                         (suggested completion)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can just press right arrow to accept the suggested completion, saving much more time than rewriting the entire command.&lt;/p&gt;
&lt;h3&gt;syntax highlighting&lt;/h3&gt;
&lt;p&gt;Fish will automatically highlight valid commands in one color and invalid ones in another. You&apos;ll know if you made a typo in a command before you press enter.&lt;/p&gt;
&lt;h3&gt;(good) tab completion&lt;/h3&gt;
&lt;p&gt;Fish can complete a ton of things. Some examples include file paths, commands and flags, git branches, environment variables, scripts from your package.json, and more. The completions for commands and flags are generated automatically based on man pages.&lt;/p&gt;
&lt;p&gt;An example showing the tab completion for &lt;code&gt;git commit -&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ git commit - # press tab here
-a  --all                     (Automatically stage modified and deleted files)
-C  --reuse-message   (Reuse log message and authorship of an existing commit)
-c  --reedit-message  (Like --reuse-message, but allow editing commit message)
-e  --edit                 (Further edit the message taken from -m, -C, or -F)
-h  --help                                   (Display manual of a Git command)
-m  --message                    (Use the given message as the commit message)
-p  --patch                        (Use interactive patch selection interface)
…and 14 more rows
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An example showing the tab completion for &lt;code&gt;$&lt;/code&gt; (environment variable):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ echo $ # press tab here
$COLORTERM                                               (Variable: truecolor)
$COLUMNS                                                        (Variable: 78)
$EDITOR                                                       (Variable: nano)
$EUID                                                          (Variable: 501)
…and 114 more rows
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;better scripting syntax&lt;/h3&gt;
&lt;p&gt;The scripting syntax in fish is a lot more understandable and easier to read than the syntax in bash. Here&apos;s an example, taken from their website:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function detect_os
    switch (uname)
        case Linux
            echo &quot;You&apos;re on Linux!&quot;
        case Darwin
            echo &quot;You&apos;re on macOS!&quot;
        case &apos;*&apos;
            echo &quot;Unknown OS: &quot;(uname)
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;compared to bash:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;detect_os() {
    case &quot;$(uname)&quot; in
        &quot;Linux&quot;)
            echo &quot;You&apos;re on Linux!&quot;
            ;;
        &quot;Darwin&quot;)
            echo &quot;You&apos;re on macOS!&quot;
            ;;
        *)
            echo &quot;Unknown OS: $(uname)&quot;
            ;;
    esac
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;configuration through web browser&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;fish_config&lt;/code&gt; and it opens a web interface where you can customize colors and prompt. You can still configure it without a web browser if you want though.&lt;/p&gt;
&lt;h2&gt;installation&lt;/h2&gt;
&lt;p&gt;You can easily install fish on Linux, MacOS and BSD. See their &lt;a href=&quot;https://fishshell.com&quot;&gt;home page&lt;/a&gt; for installation info. The &lt;a href=&quot;https://fishshell.com/docs/current&quot;&gt;documentation&lt;/a&gt; also has much more information about what it can do, how to use it, and how to set it as your default shell.&lt;/p&gt;
&lt;h2&gt;starship&lt;/h2&gt;
&lt;p&gt;After installing fish, you can use &lt;a href=&quot;https://starship.rs&quot;&gt;starship&lt;/a&gt; with it, which is a prompt thats very fast, customizable, and intelligent. It shows various things to you such as git status (current branch, changes, ahead/behind), language/package versions, ssh status, and a bunch of other information, all in a concise way.&lt;/p&gt;
&lt;p&gt;Starship is &lt;strong&gt;not&lt;/strong&gt; a shell, it&apos;s a &lt;em&gt;prompt&lt;/em&gt; for any shell. I got confused about that when I heard of these two being used together, as I thought they were both shells. You can also use it with bash, zsh, powershell, etc.&lt;/p&gt;
&lt;p&gt;For example, here I&apos;m connected to my server (coolbox) with ssh, currently in a git repository (nixflake) on the main branch, and starship lists all of that information:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;devin in 🌐 coolbox in nixflake on 🪾 main
❯ echo &quot;hi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use it with fish after installing starship, just add this to your &lt;code&gt;~/.config/fish/config.fish&lt;/code&gt; so it runs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;starship init fish | source
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully this helps!! :) This is my first blog post so if there&apos;s anything I need to correct then please lmk&lt;/p&gt;
</content:encoded><category>terminal</category><category>fish</category><category>starship</category></item><item><title>goodbye GitHub, hello Tangled (pt 1)</title><link>https://devins.page/blog/moving-from-github/</link><guid isPermaLink="true">https://devins.page/blog/moving-from-github/</guid><description>new horizons</description><pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For a very long time now, I&apos;ve been contemplating switching away from GitHub and finding a better alternative. I have felt this for various reasons, which I feel I shouldn&apos;t need to explain, but here&apos;s a little summary of issues that I&apos;ve seen from my own experiences and a couple of my friends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI has been getting very buggy and slow over the years. I&apos;ve noticed significant slowdowns especially when browsing GitHub on my phone, which I do often&lt;/li&gt;
&lt;li&gt;Occasional service reliability issues, atleast in my area. There&apos;s been cases recently where I haven&apos;t been able to download releases for some reason or even visit the site&lt;/li&gt;
&lt;li&gt;Their intrusive push for AI, including Copilot, and losing focus on what really matters - the developer experience (see &lt;a href=&quot;https://github.com/pluiedev/flake/blob/sayonara-gh/README.md&quot;&gt;Leah&lt;/a&gt;&apos;s take on this, I share a lot of the same sentiment)&lt;/li&gt;
&lt;li&gt;Owned by Microsoft, and haven&apos;t introduced any innovative features since the acquisition (2018!)&lt;/li&gt;
&lt;li&gt;Many, many, many other complaints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyways. The only realistic options I&apos;ve had other than GitHub for a while were either using &lt;a href=&quot;https://gitlab.com&quot;&gt;GitLab&lt;/a&gt;, &lt;a href=&quot;https://codeberg.org&quot;&gt;Codeberg&lt;/a&gt; or self-hosting my own Git forge. And here&apos;s a few reasons why I haven&apos;t switched to any of those.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I heavily dislike GitLab&lt;/strong&gt;. It has so many performance issues and such a steep learning curve with it&apos;s very complex, cluttered and unintuitive UI. I just really never enjoyed using it, and that could also deter contributors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Codeberg is not bad by any means&lt;/strong&gt;, and I love what they do and stand for! However, nearly every time I&apos;ve tried to switch to it I&apos;ve had issues with it taking forever to load or not loading at all. Maybe I&apos;m just very unlucky, idk. This seemed to have been a reoccurring issue for me and if I&apos;m using a software forge I need it to be reliable.&lt;/p&gt;
&lt;p&gt;And lastly, &lt;strong&gt;self-hosting a Git forge&lt;/strong&gt;, from my perspective, can be a pain to deal with and is just not worth it for me. Because most of the time, from my knowledge, you have to run a mail server, set up your own account system, and setup oauth. I find it overkill, and it also deters collaborators as they have to make new accounts specifically to PR to my projects. And yes, while I am technically &quot;self-hosting&quot; &lt;a href=&quot;https://tangled.org&quot;&gt;Tangled&lt;/a&gt;, &lt;em&gt;I&apos;ll get to why that&apos;s different&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;..so, what is Tangled? and why?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tangled.org&quot;&gt;Tangled&lt;/a&gt; is a decentralized Git hosting and collaboration platform, and these are reasons why I&apos;ve been using it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using Tangled gives you the best of both worlds: the backend (Git storage and CI) that contains the data you actually care about is decentralized and can be &lt;a href=&quot;https://docs.tangled.org/knot-self-hosting-guide.html&quot;&gt;self-hosted&lt;/a&gt;, as in &lt;strong&gt;you can own all of your data&lt;/strong&gt;. however, Tangled has a centralized frontend (App View) which acts as a consolidated view into the entire network, including those self-hosted instances. It keeps everything connected, and also simplifies self-hosting.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;For future reference, Tangled calls their Git storage servers &quot;Knots&quot; and their CI servers &quot;Spindles&quot;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;As an example, if I wanted to access my friend&apos;s repository on Tangled, I just go to &lt;code&gt;https://tangled.org/friend2.org/coolproject&lt;/code&gt;, &lt;em&gt;even if they are hosting the data themselves&lt;/em&gt;. I don&apos;t have to fiddle with accounts or anything, I can stay on Tangled.&lt;/li&gt;
&lt;li&gt;This means that people self-hosting a Tangled Knot don&apos;t have to go through the complexities of setting up account management, or a mail server, or anything like that. It only took me about 15 minutes to set up my own personal server.&lt;/li&gt;
&lt;li&gt;And of course, if you don&apos;t want to deal with self-hosting, you can just use Tangled&apos;s own storage and CI server aswell, which they provide for free. I just prefer to be able to easily back up and manage all my important data at any time, &lt;a href=&quot;https://about.gitlab.com/blog/gitlab-dot-com-database-incident&quot;&gt;in case something like the GitLab incident happened again&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/moving-from-github/knotdiagram.png&quot; alt=&quot;a diagram showing 3 knot instances, 2 of them self hosted and one of them hosted by tangled. it explains how, when the user enters certain Tangled urls, they can access repos from certain knots.&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tangled is built on &lt;a href=&quot;https://atproto.com&quot;&gt;ATProto&lt;/a&gt;, so you can optionally use a Bluesky account for login. Many people have Bluesky accounts nowadays, so you can just log in with that and you&apos;re good to go. No need to deal with manage a separate account, which is what tends to turn most people away.
&lt;ul&gt;
&lt;li&gt;If you weren&apos;t aware, you can actually self-host your Bluesky account and it&apos;s data (they call it a Personal Data Server). The Personal Data Server contains your user and post data on Bluesky, along with user data for other ATProtocol services like Tangled.&lt;/li&gt;
&lt;li&gt;Bluesky operates their own PDS under &lt;code&gt;bsky.social&lt;/code&gt;, which is the most popular PDS and is what most people use. Tangled also operates a PDS under &lt;code&gt;tangled.sh&lt;/code&gt;. And, &lt;a href=&quot;https://github.com/bluesky-social/pds&quot;&gt;you can host your own&lt;/a&gt; aswell. You can even &lt;a href=&quot;https://pdsmoover.com&quot;&gt;painlessly migrate&lt;/a&gt; all of your data between PDS&apos;s, without losing any followers or data as each person has a unique ID that doesn&apos;t change.
&lt;ul&gt;
&lt;li&gt;I recommend checking out the &lt;a href=&quot;https://at-me.zzstoatzz.io&quot;&gt;@me&lt;/a&gt; website if you want a visual representation of how the PDS works. Try entering in your Bluesky handle after logging in to Tangled with your Bluesky PDS!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tangled&apos;s UI/UX design is amazingly simple, easy to understand, and very lightweight. So much so, that I even spent a day or two redesigning my entire website around this style. That&apos;s how much I enjoy it (okay well my website also just looked like total dogshit before, as I was lazy, but whatever...)&lt;/li&gt;
&lt;li&gt;Tangled&apos;s pull request model is far superior to GitHub&apos;s. It follows a round-based pull request flow, with inter-diffing between rounds. You can just paste a &lt;code&gt;git diff&lt;/code&gt;/&lt;code&gt;git format-patch&lt;/code&gt; if you want to make quick changes! Of course, you can also just compare a fork as usual.&lt;/li&gt;
&lt;li&gt;If you self-host your CI server, you can run workflows on your own infrastructure. And, it natively supports &lt;a href=&quot;https://github.com/NixOS/nixpkgs&quot;&gt;Nix&lt;/a&gt;, so you have access to pretty much any package you need. &lt;em&gt;Seriously, &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;Nixpkgs has everything&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&apos;s a lot to love about Tangled as a code hosting service. They learned from the mistakes of previous software forges and made something very nice to use and polished. However, it is important to keep in mind that Tangled is very new. It&apos;s still in alpha, and is rapidly developing. At this time, it is currently missing a few features you may need which other forges offer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Private repositories are not a feature yet&lt;/li&gt;
&lt;li&gt;You can&apos;t run workflows on a cron job yet (to my knowledge)&lt;/li&gt;
&lt;li&gt;There is no built-in static site hosting
&lt;ul&gt;
&lt;li&gt;However, there are projects such as &lt;a href=&quot;https://wisp.place&quot;&gt;wisp.place&lt;/a&gt; which offer free static site hosting, integrated with ATProtocol. I&apos;m currently using that to host this site right now, and you can find my automatic deploy workflow on my &lt;a href=&quot;https://tangled.org/devins.page/devins.page/blob/main/.tangled/workflows/wisp-deploy.yaml&quot;&gt;devins.page/devins.page&lt;/a&gt; repository on Tangled.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Still a somewhat small userbase at the moment. It may be cumbersome to explain what Tangled is, which is exactly why I wrote this!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As much as I would like to, I won&apos;t be &lt;em&gt;fully&lt;/em&gt; switching away from GitHub. I&apos;ll still be using GitHub for my &lt;a href=&quot;https://github.com/skywardmc&quot;&gt;organization&lt;/a&gt;, along with my most popular projects such as &lt;a href=&quot;https://github.com/intergrav/devins-badges&quot;&gt;devins-badges&lt;/a&gt;. I also still need to use it to contribute to most projects. However, I will be migrating my personal projects over. Maybe once Tangled is more mature I&apos;ll consider moving the other stuff.&lt;/p&gt;
&lt;p&gt;But overall I&apos;ve been very happy with the service these past couple days and I&apos;m extremely ecstatic for what&apos;s to come. At some point I intend on making a &quot;part 2&quot; to this article explaining my experience migrating to Tangled, and possibly making a little guide to hosting your own Knot/Spindle (however I only really have ever done it on NixOS so it might just be better for you to follow the official documentation).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Please keep in mind: I am very new to this as I have only looked into ATProtocol and discovered Tangled pretty recently, so I could be wrong about some of the things I said regarding AT/Tangled in this article. Let me know if I should maybe edit anything. This is also one of my first proper articles I&apos;ve ever written. I&apos;ll be writing more.&lt;/em&gt;&lt;/p&gt;
</content:encoded><category>open-source</category><category>github</category><category>tangled</category><category>microslop</category></item><item><title>restray, a system tray GUI for restic</title><link>https://devins.page/blog/restray/</link><guid isPermaLink="true">https://devins.page/blog/restray/</guid><description>my simple, cross-platform backup solution</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;(This is, for the most part, a copy of the post I wrote on the &lt;a href=&quot;https://forum.restic.net/t/restray-a-simple-cross-platform-system-tray-ui-for-restic/10915&quot;&gt;restic forum&lt;/a&gt; with minor edits)&lt;/p&gt;
&lt;p&gt;For various reasons[^1] I&apos;ve been looking to move away from Time Machine. I also needed to help my brother set up backups for his computer as the other &lt;a href=&quot;https://support.microsoft.com/en-US/Windows/Experience/Backup-Recovery/backup-restore-and-recovery-in-windows&quot;&gt;backup&lt;/a&gt; &lt;a href=&quot;https://www.veeam.com/&quot;&gt;programs&lt;/a&gt; we tried were just not reliable enough and didn&apos;t work for our use case.&lt;/p&gt;
&lt;p&gt;Looking for solutions, I decided to go with restic as I&apos;ve already been using it on my servers for years and absolutely love it. But then I realized I needed some sort of wrapper to make it easier to work with on a desktop OS. I&apos;ve looked at &lt;a href=&quot;https://github.com/creativeprojects/resticprofile&quot;&gt;resticprofile&lt;/a&gt; and &lt;a href=&quot;https://github.com/garethgeorge/backrest&quot;&gt;Backrest&lt;/a&gt;, and I certainly think they&apos;re great projects! But for my use case, I wanted something even simpler. Like Time Machine if it was instead open-source and cross-platform and modern and Actually Good.&lt;/p&gt;
&lt;h2&gt;here it is&lt;/h2&gt;
&lt;p&gt;So, I started writing my own wrapper in Go, and called it Restray[^2]. The intent was to make a very simple and intuitive scheduler for restic that can be used on any OS. It sits in the system tray and all of the functionality is accessible through the tray menu. You can configure and set it up through a config file, or optionally use the very barebones web-based editor through your browser.&lt;/p&gt;
&lt;p&gt;Other than the browser-based config editor, there is no web tech involved. So, at idle, the app uses just ~30MB memory and little-to-no CPU. That scales when you start a backup of course, since restic does require quite a bit of memory while running. But it&apos;s generally very lightweight.&lt;/p&gt;
&lt;p&gt;Here&apos;s a preview of Restray on MacOS, but it also works great on Linux and Windows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/restray/macos.jpg&quot; alt=&quot;A screenshot of restray&apos;s tray menu on MacOS&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of the web editor, but you can also just configure with a text editor of course[^3]:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/restray/webeditor.png&quot; alt=&quot;A screenshot of restray&apos;s web config editor&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;some cool features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Simple scheduling, just input a cron expression. To avoid complexity it runs in the background with it&apos;s own scheduler, so you don&apos;t have to deal with Task Scheduler/launchd/systemd/whatever else is out there[^4]&lt;/li&gt;
&lt;li&gt;Restray supports multiple backup profiles, each with their own schedule, environment file, and settings, which can be useful for having both on-site and off-site backups (in my case, rest HTTP server, and OneDrive through rclone)&lt;/li&gt;
&lt;li&gt;If restic is not found in your PATH, on Windows and Linux Restray can self-manage it&apos;s own restic binary from GitHub and update it daily[^5]. The MacOS &lt;code&gt;.app&lt;/code&gt; also has the latest restic binary bundled at build time&lt;/li&gt;
&lt;li&gt;If you need to restore something, on MacOS and Linux you can easily run &lt;code&gt;restic mount&lt;/code&gt; from the Operations menu, assuming you have FUSE
&lt;ul&gt;
&lt;li&gt;I am also working on a cross-platform QT repository browser that will integrate with Restray, however it will be a separate project and program which you can use standalone. As an alternative to the web-based &lt;a href=&quot;https://github.com/emuell/restic-browser&quot;&gt;restic-browser&lt;/a&gt;. I will post about that later if I ever do end up finishing it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Offers a &quot;Shell&quot; operation that lets you instantly drop into your default terminal with the selected profile&apos;s environment file sourced, and restic binary loaded into your PATH, allowing you to do more advanced CLI things without friction. works on Windows too!&lt;/li&gt;
&lt;li&gt;Can be configured to detect whether or not the machine is on battery power, and based on that, pause the schedule.&lt;/li&gt;
&lt;li&gt;Pretty icon animations that I spent a lot of time on for no reason because I was bored&lt;/li&gt;
&lt;li&gt;Config file hot-reloading&lt;/li&gt;
&lt;li&gt;Hooks&lt;/li&gt;
&lt;li&gt;Flexible configuration&lt;/li&gt;
&lt;li&gt;See the &lt;a href=&quot;https://tangled.org/devins.page/restray&quot;&gt;README&lt;/a&gt; for even more features and config reference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the future, I also plan on supporting alternative backends, the one I have in mind being &lt;a href=&quot;https://rustic.cli.rs&quot;&gt;rustic&lt;/a&gt; for better resource usage and lock-free operations. Maybe Borg too but I&apos;ve never used that personally...&lt;/p&gt;
&lt;h2&gt;a little disclaimer&lt;/h2&gt;
&lt;p&gt;While me and my brother have been using Restray for a little while now without issues, this is still pretty new stuff and if you experience any bugs please make an &lt;a href=&quot;https://tangled.org/devins.page/restray/issues&quot;&gt;issue&lt;/a&gt; and I&apos;ll happily look into it.&lt;/p&gt;
&lt;h2&gt;ok but how do I get it&lt;/h2&gt;
&lt;p&gt;For most releases I compile and upload binaries for Windows, Linux, and Darwin (MacOS) and you can get them on &lt;a href=&quot;https://tangled.org/devins.page/restray/tags&quot;&gt;this page&lt;/a&gt;. If you&apos;re on MacOS, keep in mind that the MacOS app is not signed/notarized so you will need to &lt;a href=&quot;https://disable-gatekeeper.github.io/#disabling-gatekeeper-for-one-application-only&quot;&gt;remove it&apos;s quarantine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But you can also compile it from source if you&apos;d like, all you need is Go. I also have a Nix package and NixOS module available in the repo&apos;s flake :^)&lt;/p&gt;
&lt;h2&gt;ok but how do I use it&lt;/h2&gt;
&lt;p&gt;It should hopefully be relatively straightforward to use for anyone who&apos;s familiar with restic, but I may make a little guide or video in the future on setting it up. Generally all you have to do is run it, configure the repository path and password in the env file, and configure paths, cron schedule, or arguments in the config file.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Releasing this in case someone finds this useful. I&apos;ve been wanting to get into desktop software development for a while (less web dev...) and I&apos;m pretty new to this, so if you have any suggestions on improving Restray, let me know on the &lt;a href=&quot;https://tangled.org/devins.page/restray/issues&quot;&gt;issue tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;m probably going to refrain from adding new features though, since it appears to be mostly feature-complete in my eyes. I want to focus more on refining the UX and codebase where possible though I think it&apos;s in a pretty good state right now.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/restray&quot;&gt;Here&apos;s a cool landing page I made&lt;/a&gt; if you want a summary...&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[^1]: Time Machine is not cross-platform, which means I can&apos;t have one consistent backup manager across all of my devices. And Apple is phasing out AFP in the next version of MacOS which means I&apos;d have to use SMB which tends to be &lt;em&gt;slow&lt;/em&gt;. Though Time Machine is also just slow in general... And restic is just awesome.&lt;/p&gt;
&lt;p&gt;[^2]: waow. restic + tray. what a revolutionary name...&lt;/p&gt;
&lt;p&gt;[^3]: In this particular screenshot it says read-only because my config is managed by Restray&apos;s Home Manager module, but if you&apos;re not an insane NixOS user you can just edit it&lt;/p&gt;
&lt;p&gt;[^4]: But if you want to, you can! Restray can also be executed through CLI/daemon on Linux/MacOS, see &lt;code&gt;restray --help&lt;/code&gt; for a list of commands. But at that point you might just wanna use resticprofile&lt;/p&gt;
&lt;p&gt;[^5]: Configurable with the &lt;code&gt;manage_restic&lt;/code&gt; setting, unavailable in CLI/daemon&lt;/p&gt;
</content:encoded><category>restray</category><category>go</category><category>open-source</category><category>backups</category></item><item><title>site changes and other updates</title><link>https://devins.page/blog/site-changes/</link><guid isPermaLink="true">https://devins.page/blog/site-changes/</guid><description>some small changes to devins.page, and other stuff</description><pubDate>Sat, 20 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;&lt;s&gt;Using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/system-color&quot;&gt;system colors&lt;/a&gt; again, since I didn&apos;t like the color scheme I came up with.&lt;/s&gt; I made a new beige color scheme that I quite like, so this will probably stick for a while&lt;/li&gt;
&lt;li&gt;&lt;s&gt;Removed &lt;a href=&quot;https://giscus.app&quot;&gt;giscus&lt;/a&gt; comments since they were never really used and just adds bloat to the page. Maybe in the future I&apos;ll make a simpler comments system.&lt;/s&gt; I&apos;ve added it back, and mentioned it in the privacy page&lt;/li&gt;
&lt;li&gt;Redesigned the header to be a lot more simple, moved external links to the footer.&lt;/li&gt;
&lt;li&gt;Use serif fonts for headings, handwritten font for site title, just because I think it looks more pleasing.&lt;/li&gt;
&lt;li&gt;Removed &lt;a href=&quot;https://docs.astro.build/en/guides/view-transitions&quot;&gt;clientrouter&lt;/a&gt; which gets rid of site transitions, I felt like it didn&apos;t really fit well with this site and some browsers couldn&apos;t handle it properly.&lt;/li&gt;
&lt;li&gt;Added back link underlines for accessibility&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides that, I&apos;m planning on maybe working on a few new projects in the coming months.&lt;/p&gt;
&lt;h2&gt;litedocs&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Edit 5/18/26: This has been scrapped for a long time, I forgot I was even working on this&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was working on a documentation theme for &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt;, similar to &lt;a href=&quot;https://starlight.astro.build&quot;&gt;Starlight&lt;/a&gt;. The main difference is that it will be &lt;em&gt;far, far&lt;/em&gt; more lightweight and minimal (like this current site). I haven&apos;t come up with a final name yet but I&apos;ll probably just call it &quot;litedocs&quot; or something. Once that&apos;s done, I may redesign the &lt;a href=&quot;https://skywardmc.org&quot;&gt;SkywardMC site&lt;/a&gt; to use that, so I can test it and make sure it works properly. It&apos;ll include the necessary stuff such as site-wide search with the &lt;a href=&quot;https://pagefind.app&quot;&gt;pagefind api&lt;/a&gt;, a customizable sidebar for nav and external links, and internationalization.&lt;/p&gt;
&lt;p&gt;While working on this, I had to make a lot of changes to &lt;a href=&quot;https://slightcss.devins.page&quot;&gt;slight.css&lt;/a&gt; to make it work better. So, that may get a new major version aswell. It mainly includes some cleanup and new variables to work with.&lt;/p&gt;
&lt;p&gt;If/when this project is released, I&apos;ll make a post about it here. Maybe I&apos;ll also work on similar projects, like a blog theme. Slight.css, this project, and other stuff like that will probably be in under it&apos;s own organization.&lt;/p&gt;
</content:encoded><category>meta</category></item><item><title>tricks to make web apps feel native</title><link>https://devins.page/blog/web-native-laf/</link><guid isPermaLink="true">https://devins.page/blog/web-native-laf/</guid><description>various tricks to help make web apps look native to the system and also improve usability</description><pubDate>Mon, 18 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For a few months I&apos;ve been working on a music player for &lt;a href=&quot;https://opensubsonic.netlify.app&quot;&gt;OpenSubsonic&lt;/a&gt; servers (&lt;a href=&quot;http://navidrome.org&quot;&gt;Navidrome&lt;/a&gt;, &lt;a href=&quot;https://github.com/sentriz/gonic&quot;&gt;Gonic&lt;/a&gt;, etc) called &lt;a href=&quot;/tinysub&quot;&gt;tinysub&lt;/a&gt;. Rather than a Qt or SwiftUI app, I went with a web app so that this could run on any device easily.&lt;/p&gt;
&lt;p&gt;One of the biggest things I focused on while developing this app was &lt;strong&gt;performance&lt;/strong&gt;, which &lt;a href=&quot;https://svelte.dev&quot;&gt;Svelte&lt;/a&gt; and &lt;a href=&quot;https://vite.dev&quot;&gt;Vite&lt;/a&gt; mostly solved for me. But another thing I focused on was making it &lt;strong&gt;look and feel like a native application&lt;/strong&gt;, atleast on MacOS.[^1] So I wanted to write down some notes about my experience, in case it might help someone in the future.&lt;/p&gt;
&lt;p&gt;Here&apos;s examples of how it turned out:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/example1.png&quot; alt=&quot;example screenshot of the tinysub app running in a tauri window&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/example2.png&quot; alt=&quot;example screenshot of the tinysub app running in a tauri window, in miniplayer mode&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m using &lt;a href=&quot;https://tauri.app&quot;&gt;Tauri&lt;/a&gt; to build tinysub, however I&apos;m sure you could probably achieve all the same things with &lt;a href=&quot;https://www.electronjs.org&quot;&gt;Electron&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;tricks&lt;/h2&gt;
&lt;h3&gt;1. use system font size and family&lt;/h3&gt;
&lt;p&gt;On MacOS (seemingly Windows too), most native applications typically use 13px (0.8125rem) font size by default for most elements. Browsers typically use 16px (1rem) font size by default. Changing the default font size can make a huge difference in how your application looks and feels compared to native, and having a smaller font size also lets you fit much more on the screen!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
	font-size: 0.8125rem;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unless you are choosing a specific font for your brand, I recommend using the system font (San Francisco on MacOS, Segoe UI on Windows). Not only does this make your app bundle lighter, since you&apos;re not bundling any fonts, it also looks more consistent with the rest of the operating system. This is what I typically use, leaving &lt;code&gt;sans-serif&lt;/code&gt; as a fallback for compatibility:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
	font-family: ui-sans-serif, system-ui, sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/fontsize.png&quot; alt=&quot;screenshots showing web app with 16px and 13px fonts, and a native app using default font size for comparison&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;2. some CSS properties to change&lt;/h3&gt;
&lt;p&gt;In the HTML element, you should probably disable &lt;code&gt;user-select&lt;/code&gt; (and &lt;code&gt;-webkit-user-select&lt;/code&gt; for Safari) so that your user can&apos;t select text, which stays consistent with native apps. You may want to re-enable this for body copy.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
	-webkit-user-select: none;
	user-select: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recommend disabling overscroll so that you don&apos;t get that &quot;elastic scroll&quot; effect on the main window, which is seen when scrolling on trackpads or mobile devices:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
	overscroll-behavior: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recommend hiding the tap highlight on iOS devices, which usually causes a blue tint when you press a button:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
	-webkit-tap-highlight-color: transparent;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. use proper viewport sizing&lt;/h3&gt;
&lt;p&gt;Mobile browsers dynamically shift and resize their search and action elements to make more space for the page. The typical &lt;code&gt;vh&lt;/code&gt; and &lt;code&gt;vw&lt;/code&gt; units do not dynamically change with those elements, often causing the viewport to exceed the browser view area. To mitigate this, use &lt;code&gt;dvh&lt;/code&gt; and &lt;code&gt;dvw&lt;/code&gt;, which &lt;em&gt;do&lt;/em&gt; dynamically change. (for more details, check out this &lt;a href=&quot;https://dev.to/frehner/css-vh-dvh-lvh-svh-and-vw-units-27k4&quot;&gt;article&lt;/a&gt; by Anthony Frehner)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
	height: 100dvh;
	width: 100dvw;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. adjust whitespace for safe-area&lt;/h3&gt;
&lt;p&gt;Another thing you should consider is adjusting whitespace for safe-area. For example, on an edge-to-edge phone where rounded corners are part of the screen, buttons in a footer/action bar could be impossible to reach if they are located behind those rounded corners, or otherwise uncomfortable to reach if they are too close to the bottom edge of the display.&lt;/p&gt;
&lt;p&gt;Luckily, this is very easy to solve, thanks to the CSS &lt;code&gt;env(safe-area-inset-*)&lt;/code&gt; variables which dynamically change based on the device you&apos;re viewing on. In this case I went with borders instead of padding so that I could customize the color of the whitespace for each side, such as matching the bottom whitespace with the footer color of my app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
	border-top: env(safe-area-inset-top) solid transparent;
	border-right: env(safe-area-inset-right) solid transparent;
	border-left: env(safe-area-inset-left) solid var(--bg-sidebar);
	border-bottom: env(safe-area-inset-bottom) solid var(--bg-footer);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On desktop these will typically have no effect but you will notice it on mobile devices:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/safe-area.png&quot; alt=&quot;comparison of safe area and no safe area whitespace on a mobile device&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;5. use native context menus&lt;/h3&gt;
&lt;p&gt;In Tauri/Electron apps, I recommend using native context menus, which tend to be more accessible, more consistent, and gives you less code to deal with than making your own custom context menu. In tinysub specifically, I use a custom context menu in the web builds, and native context menus in the Tauri builds.&lt;/p&gt;
&lt;p&gt;Here&apos;s the &lt;a href=&quot;https://v2.tauri.app/learn/window-menu&quot;&gt;Tauri&lt;/a&gt; and &lt;a href=&quot;https://www.electronjs.org/docs/latest/tutorial/context-menu&quot;&gt;Electron&lt;/a&gt; documentation to get started, and here&apos;s what it can look like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/contextmenu.png&quot; alt=&quot;comparison of system vs native context menu&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;6. consider a custom titlebar&lt;/h3&gt;
&lt;p&gt;You may want to consider a custom titlebar. Doing so can allow the titlebar to flow better with your content, or allow you to save space by placing actions in the titlebar itself. Personally, I did not make a custom titlebar for tinysub as I felt it wasn&apos;t necessary, and custom titlebars can often be a bit annoying on Linux.&lt;/p&gt;
&lt;p&gt;Here&apos;s the &lt;a href=&quot;https://tauri.app/learn/window-customization/#creating-a-custom-titlebar&quot;&gt;Tauri&lt;/a&gt; and &lt;a href=&quot;https://www.electronjs.org/docs/latest/tutorial/custom-title-bar&quot;&gt;Electron&lt;/a&gt; documentation to get started on custom titlebars.&lt;/p&gt;
&lt;h3&gt;7. only show window after page is loaded&lt;/h3&gt;
&lt;p&gt;I recommend disabling window visibility on startup, and then have your app code show the window only once the page is ready. This prevents any flashing or blank screens while your app is loading.&lt;/p&gt;
&lt;p&gt;Here&apos;s some snippets from my app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let window = WebviewWindowBuilder::new((app, &quot;main&quot;.to_string(), WebviewUrl::External(url)))
	.title(&quot;tinysub&quot;)
	.visible(false) // hide window initially, javascript code will unhide later
	//...other window properties
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;export const init = async () =&amp;gt; {
	//...code to execute before showing the window
	if (isTauri) {
		const { getCurrentWindow } = await import(&quot;@tauri-apps/api/window&quot;);
		const win = getCurrentWindow();
		await win.show();
		await win.setFocus();
	}
	//...code to execute after window is done showing
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. window blur/vibrancy&lt;/h3&gt;
&lt;p&gt;On MacOS and Windows, it&apos;s relatively easy to achieve blur behind sidebars in Tauri with the &lt;a href=&quot;https://github.com/tauri-apps/window-vibrancy&quot;&gt;window-vibrancy&lt;/a&gt; plugin. Vibrancy is possible on Linux desktops too, though on Linux, the compositor is what applies the effect, not the application itself, and only certain compositors support blur (i.e. kwin).&lt;/p&gt;
&lt;p&gt;Here&apos;s a snippet from my app, though I&apos;d recommend reading the full documentation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use window_vibrancy::*;

// macos vibrancy (using sidebar material)
#[cfg(target_os = &quot;macos&quot;)]
apply_vibrancy(&amp;amp;window, NSVisualEffectMaterial::Sidebar, None, None)
	.expect(&quot;unsupported platform! &apos;apply_vibrancy&apos; is only supported on macOS&quot;);

// windows vibrancy (using mica material)
#[cfg(target_os = &quot;windows&quot;)]
apply_mica(&amp;amp;window, None)
	.expect(&quot;unsupported platform! &apos;apply_mica&apos; is only supported on Windows 11&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will need to enable transparency in the Tauri window builder. After that, make sure to set the body&apos;s &lt;code&gt;background-color&lt;/code&gt; to &lt;code&gt;transparent&lt;/code&gt; so that you can actually see through the app, and then apply opaque colors to the main app section (in this case the song queue), leaving the sidebar transparent.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let window = WebviewWindowBuilder::new((app, &quot;main&quot;.to_string(), WebviewUrl::External(url)))
	.title(&quot;tinysub&quot;)
	.transparent(true) // needed to see window-vibrancy effect
	//...other window properties
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;body {
	background: transparent;
}

#queue {
	background: Canvas;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This effect can really help make your app feel more consistent with the rest of the system, though I&apos;d recommend making transparency configurable for Linux users who don&apos;t have a compositor that supports blur. And then that gives you this beautiful transparency effect:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/blog/web-native-laf/translucency.png&quot; alt=&quot;window translucency example&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;9. styling tips&lt;/h3&gt;
&lt;p&gt;In tinysub I often used some OS-specific styling, such as a different color for the sidebar/titlebar borders to match native MacOS apps. I also used custom colors for item selection on MacOS. Tiny tweaks like these can make a big difference in how your app feels, even if the user doesn&apos;t notice it.&lt;/p&gt;
&lt;p&gt;In a lot of cases I actually just avoided hard-coded colors entirely unless where necessary. Instead I opted to utilize the CSS &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/system-color&quot;&gt;&lt;code&gt;&amp;lt;system-color&amp;gt;&lt;/code&gt;&lt;/a&gt; type for various colors, and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/color-scheme&quot;&gt;&lt;code&gt;color-scheme&lt;/code&gt;&lt;/a&gt; property for light/dark mode. It can be a lot simpler to write this way and also look more consistent with other applications, unless you have specific colors in mind for your brand.&lt;/p&gt;
&lt;h3&gt;10: other tricks&lt;/h3&gt;
&lt;p&gt;For even more tricks on making your app feel native, this &lt;a href=&quot;https://getlotus.app/21-making-electron-apps-feel-native-on-mac&quot;&gt;article&lt;/a&gt; by &lt;a href=&quot;https://vadimdemedes.com&quot;&gt;Vadim Demedes&lt;/a&gt; is a great resource. I just wrote this article to add on some other ideas too.&lt;/p&gt;
&lt;h2&gt;ending notes&lt;/h2&gt;
&lt;p&gt;Apologies if this article is a little sloppy, these were just notes that I personally wrote for myself while developing tinysub. Hopefully it was useful to you or informational in any way. If you have any suggestions, let me know in the comments and I&apos;ll edit the article accordingly.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[^1]: When I am referring to &quot;a native look on MacOS&quot;, I am specifically referring to pre-Tahoe design. I don&apos;t intend on implementing Liquid Glass elements into my app as it&apos;s tricky to do in CSS, would be far too heavy, and I am personally not a fan of it regardless. However, the &lt;a href=&quot;https://github.com/aaaaalexis/obsidian-cupertino&quot;&gt;Cupertino theme&lt;/a&gt; for Obsidian does an excellent job on emulating the MacOS Tahoe design if you&apos;d like to see an example of that.&lt;/p&gt;
</content:encoded><category>open-source</category><category>web</category><category>tauri</category></item><item><title>the blog is up</title><link>https://devins.page/blog/welcome/</link><guid isPermaLink="true">https://devins.page/blog/welcome/</guid><description>this is my first blog post! this is just a test post so i can make sure everything works</description><pubDate>Mon, 23 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I know this website may look very dull - I like it, and I believe that it works fine. I&apos;ll probably be implementing a theme switcher at some point for anyone that likes catppuccin or other themes.&lt;/p&gt;
</content:encoded><category>meta</category></item></channel></rss>