<?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>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>