Category: #Setup

Week 3: Visiting Family, Plan 9 Bootcamp

↗ Lo-fi version

I visited my family this week in New Jersey. It’s my grandpa’s birthday so we had a little reunion over here. My siblings are on summer vacation as well, so it’s really nice to see everyone in one place.

My parent’s house is surrounded by trees so I’ve been taking advantage of all the greenery outside. I wish I had this in Philly. I love looking away from my laptop and seeing a bunch of birds flying around. (And the occasional spider.)

Work setup on a bench outside.

I honestly don’t remember how I stumbled into this, but by some stroke of luck I ran into SDF’s Plan 9 bootcamp this week as well, and I’ve been enjoying it a lot. It’s surprising how much fun I’m having playing around with a weird operating system. I think it’s partly because it’s fun exploring a completely new system, and I think it’s partly because I’m learning with a bunch of other people at the same time. It also ties in with my interest in permacomputing because Plan 9 is much simpler compared to other operating systems so I want to see what you can do with it.

Cluttered Plan 9 desktop.

I’m struggling with the three-button mouse usage, slow browsers, and weird shell, but I’m starting to get the hang of it I think! Right now I’m watching Tea Note #2 and also writing a YNAB-like budgeting app in rc (hugely based on the excellent Plan 9 desktop guide). We’ll see how it goes.


Week 1: All over the place

↗ Lo-fi version

I’ve been learning a lot of random things recently. The other week, I signed up for an electronics course on Ohmify and bought a bunch of components and tools so that I could follow along. I’m having a lot of fun trying out the different activities on that website. I just started so I’ve only made simple circuits, so I have a lot of learning to do! I also need to get a drawer for all these components that I got online because it’s a bit of a mess right now.

Touch sensor with a transistor.

Not quite clear on what my end goal is with learning electronics, but I’d like to learn how to tinker more with computer hardware so I’m starting with the basics. Semi-related: I got an open source hardware trackball called Ploopy! I didn’t get the DIY kit so I didn’t build it myself, but I’ve been learning how to customize the firmware. Just last night I got to map one mouse button to CTRL+TAB and then another one to CTRL+SHIFT+TAB. It feels like AutoHotkey, but built-in to the device!

I’ve also been playing some DOOM II! I initially installed it on the Raspberry Pi 400 for fun (I wanted to see how well it ran), but I ended up getting hooked. I definitely didn’t expect DOOM II from 1994 to hold a candle to the latest iterations like DOOM Eternal.

I bought the game on GOG, extracted it using innoextract, then I ran the WAD file on LZDOOM. It worked like a charm.

A screenshot of DOOM II running on a Raspberry Pi 400.

I’ve been going back to kettlebell class at my gym as well. It’s been a while since I last went, so my stamina isn’t as good as it used to. I’m still struggling in class, but I feel like I’m slowly improving at least. The summer heat isn’t helping either.

Finally, I’ve been continuing to read CAPS LOCK which is a book about how design is tightly intertwined with capitalism (so far I’ve learned: building trust in the government [design of documents and money], nudging people to spend more [design of credit cards and apps], and standards for increasing efficiency [bar codes])


Hello again, Linux

I’ve been running Linux on my laptop for a little over a week now, and so far I’m really impressed with it! It’s probably almost a decade since I last used Linux (outside of Windows Subsystem for Linux and accessing remote machines) so I wanted to see how well it works as my main OS.

I moved to Windows from macOS in 2020 because it gave me more hardware options (I wanted a laptop that was more repairable), gaming options (a lot of games that I want to play run on Windows), and it still let me do my design work. Windows meets all my needs to be honest, but it makes me uncomfortable to use an OS made by a surveillance capitalist so I’m curious about an alternative and I wanted to see if Linux would work for me.

I downloaded Fedora and installed it on my Dell XPS 17.

Hardware Support

Thunderbolt works as expected. It looks gorgeous on my 5k LG Ultrafine monitor, and I’m able to run both the built-in 4k display and the 5k external display at the same time. That’s a lot of pixels! My Wacom tablet just worked out of the box. I didn’t have to download anything for it to work which was really impressive. Bluetooth and WiFi work flawlessly. I can use my Bluetooth mouse with no issue.

It unfortunately wouldn’t let me install the Nvidia driver from the app store, but I believe all I had to do was run sudo dnf install akmod-nvidia in the terminal to fix it. I can now right click on an app and run it on the Nvidia GPU.

Fingerprint reader doesn’t work, so I still need to figure that out.

Wacom support is built-in.


I downloaded Steam, enabled the Windows-compatibility option, and installed DOOM Eternal. It wasn’t working at first—it said that I didn’t have enough memory in my video card. So I lowered the quality a bit and it ran perfectly. I played 4 hours of it in Nightmare mode, so I’m pretty impressed with the speed as well! I have yet to try other games, but I’m hopeful based on the reports that I’m seeing about the Steam Deck. I’m really amazed to see what Valve has done to make Windows games work.

DOOM Eternal main menu.


I expected to have some issues with the available software, but it wasn’t actually that much of a hassle for me. Maybe I just don’t use that many apps to begin with. For 1Password, Zoom, Spotify, digiKam, Mini vMac, Telegram, Thunderbird, Sublime Text, and Signal, they work the same way as their Windows and macOS counterparts. Figma doesn’t have a desktop app, but there is an unofficial Linux version that works just fine. For Dropbox, I’m using an app called Maestral.

There’s a built-in app in GNOME for recording the screen, but it doesn’t record it in GIF format. A little app called Kooha is able to do that though. I’m also pleasantly surprised that Fedora also comes with a simple backup tool that I’m using to backup to my account.

I do wish there was AutoHotKey. And Excel. And Krisp. And Em Client.

What I’m most impressed with is that Fedora comes with virtualization software and it’s super easy to use! So I’ve been running Windows on there when I need it.

Programs installed on my laptop.

I’m not sure if I want to go Linux full time yet, but I’m excited that I’m actually using it! I think it pretty much meets my needs, but it does take a bit of work to get things working. I’m hopeful, so we’ll see what happens!

Ear Transit Released

I made a desktop app called Ear Transit! It’s a tiny tool that lets you listen to background noise on your computer even if you’re not connected to the internet. It currently has 4 background noises at the moment, but I’ll be adding more pretty soon. Right now it only runs on Windows, so I’m also hoping to port it to other operating systems when I find the time.

Playing multiple background noises on Ear Transit.

It’s written in HTML, CSS, and JS using the Sciter Engine, but I actually started out by building a prototype using Lazarus / Free Pascal. I loved the drag-and-drop interface builder and that it compiles everything to native code, but I struggled with it because I’m unfamiliar with the language and the tooling. I guess I’m just impatient, but I eventually gave up and went with the web development tools because that’s more familiar to me. I chose Sciter over Electron because of the small runtime—the whole thing weighs about 8MB compared to Electron which is at 80MB. I wanted the app to be as small as possible because all it does is play audio files.

The app at launch uses only 13MB of RAM so I’m very pleased with the leanness of the app. The memory usage does grow as you play the background noises though because the MP3s are loaded into RAM so I’ll have to look into ways of minimizing that.

Ear Transit on the app.

Head on over to to download Ear Transit! I hope you like it. I also recently released the code on Sourcehut.

Figma ♥ AutoHotKey

An illustration of a cat with the hotkey "ctrl+zzz"

I found out about AutoHotKey last week because I was looking for a lightweight alternative to Logitech Options. My plan was to remap the buttons on my mouse and be done with it. But after going through the AutoHotKey tutorial, I realized that it’s actually much more powerful than I thought. It got me excited because I felt like it could open up a whole world of customization possibilities to me.

The first thing I wanted to do with it was to improve my design workflow on Figma because I use this app quite a bit. To localize my hotkeys to Figma, I put this directive at the top of my Figma.ahk file:

; Look for Figma.exe
#IfWinActive, ahk_exe figma.exe

This means that everything written below this line will only apply to Figma.

Fast toggling between tools

Toggling between the Hand tool and Move tool.

I switch between the Hand tool (h) and the Move tool (v) a lot, but I often find myself looking down to readjust my hand on the keyboard because my left hand would rather hang out around the Ctrl and Alt keys area.

I figured it would be easier if I could switch between the tools with just my mouse. So I mapped the 4th and 5th extra buttons to h and v in AutoHotKey and that allowed me switch tools using my thumb. In AutoHotKey, these buttons are XButton1 and XButton2 so all I did was to point them to h and v respectively.

The v and h keys are now toggled using my thumb. Much easier!
; Hand Tool
; Trigger: 4th mouse button

; Move Tool
; Trigger: 5th mouse button

Switching between tabs

Moving between two tabs.

When I’m designing, I often have two tabs open: one file has the components (the component library) and another file has the instances. I move between these two files often which is why I want tab switching to be as effortless as possible.

I know that there are a few ways to switch tabs on Figma, but unfortunately none of them feel fluid to me. After some experimentation, I ended up mapping the left tilt of my scroll wheel to Ctrl + Shift + Tab and the right tilt to Ctrl + Tab. It’s simple, but it works wonderfully. It basically lets me switch tabs with just one finger!

The middle button can tilt left and right so I mapped that to switch between tabs.
; Move between tabs
; Trigger: Left and right wheel tilt

Running Figma plugins

Running quick actions and launching the Find and Replace plugin.

As far as I can tell, there’s no easy way to map a specific Figma plugin to a keyboard shortcut on Windows (you can do it on macOS though). The fastest way that I can think of is through “quick actions” which is triggered by pressing Ctrl + / and then typing in the plugin name. That got me thinking … maybe I could let AutoHotKey run quick actions and type in the plugin name for me?

This is where I started to see the power of AutoHotKey. It doesn’t just let you map a set of buttons to another set of buttons—it can also do any sort of arbitrary action for you! With my setup, whenever I press Ctrl + F, AutoHotKey runs the Find and Replace plugin by doing the following:

  1. Presses Ctrl + / to bring up quick actions.
  2. Waits a little bit because the quick actions search bar doesn’t show up instantaneously.
  3. Types in “find and replace” to bring up the plugin.
  4. Presses Return to run the plugin.

It’s hacky, but it works! I also have Component Page plugin mapped to Ctrl + Alt + K and Similayer plugin mapped to Control + Alt + F.

; Function to run Figma Plugins
FigmaPlugin(searchQuery) {
	; This triggers Quick Action
	Send, ^/
	; Issues come up when things are typed instantaneously
	Sleep 500
	; Search for the plugin
	SendInput, %searchQuery%
	Send, {Enter}

; Run the Find and Replace Plugin
; Trigger: Control+F
FigmaPlugin("find and replace")

Super Nudge

Notice the X and Y values incrementing by 100 pixels.

Figma lets you move a selection with a keyboard: pressing the arrow key moves the selection by 1px and pressing the arrow key while holding down Shift moves the selection by 10px. But what if we want to move the selection over a larger distance?

I saw the question on Figma’s forum, and I wanted to see if I can do it myself with AutoHotKey. After a bit of research, I learned that you can specify the number of key presses with a one liner—no looping needed! Here’s an example: if I wanted to hold Shift and press the left arrow key ten times, I can type in Send, +{Left 10}. That’s it. Then I mapped this to caps lock because I almost never use that key:

; Nudge selection 100px to the top/bottom/left/right
; Trigger: CapsLock+[Up/Down/Left/Right]
CapsLock & Left::Send, +{Left 10}
CapsLock & Right::Send, +{Right 10}
CapsLock & Up::Send, +{Up 10}
CapsLock & Down::Send, +{Down 10}

What’s next

It’s only been a week, but I feel like I’ve already improved my workflow thanks to AutoHotKey. I’ll definitely be tweaking things as I go but for now I feel like I’m in a good place with it. My AutoHotKey scripts can be found here.

Screencast showing tool switching (using extra mouse buttons), tab switching (using middle button), and plugin launching (using hotkeys).

Digital Spring Cleaning

A screenshot of this website.

I did some reorganizing on this website, and I think I’m pretty happy about it! The biggest thing I did was merging both and I’ve been maintaining separate WordPress sites for my professional and private blogs, but it was a pain because I had to make sure that I copy any plugin or theme changes from one server to the other.

I figured that it would be much easier to merge the two and simply label my personal updates as #personal. I think I like this more because the site is now a better representation of me now that it has both personal and professional content. It’s also easier to share with other people: just go to to see what I’m up to.

Simplifying my website felt great and it gave me the energy to cut down on some of the hosting software and services that I no longer need:

  • I was able to downgrade Cloudron (a tool for self-hosting websites) to the free tier now that I got to remove an extra WordPress site. This will save me $180 per year.
  • I also cancelled my second Akismet subscription (a service that blocks spammy comments) since I’m only running one WordPress site. This saves me $18 per year.
  • I downgraded to a smaller server on Hetzner (a hosting company) as well and this saves me €132 or $160 per year.

That’s $358 of savings a year! It looks like reorganizing pays off.

File Sharing Setup

A drawing of a puffer fish floating in the sky.

When Firefox Send shutdown, I started running my own instance of NextCloud to send files to people. It worked as expected, but it also felt slow. It felt like I was using a website that just groggily woke up from a nap whenever I logged into it.

I figured that maybe I could replace it with something leanerespecially since I felt like I didn’t need a lot of the features that NextCloud offered. I’ve recently been learning how to set up static sites on OpenBSD and it occurred to me that I could use OpenBSD’s built-in HTTP server to send files to people.

Setting up the Server

I went through the same process that I listed in my notes on setting up an OpenBSD server using httpd. You can use any other web server, but I love how simple it is to setup httpd.

Changing Write Permissions

I wanted to be able to write in the /var/www/htdocs/ as a normal user, so I changed the permissions to be owned by my user instead of root:

$ doas chown -R jag:jag /var/www/htdocs/

Easily Uploading Files

I don’t want to copy files manually to the remote server using the command line every time I wanted to send a file, so I set up Cyberduck to connect to my server using SFTP. I bet Transmit would work well too if you’re on macOS!

A screenshot of Cyberduck showing some of my remote files.

It was relatively easy to set up, but a bit intimidating. I needed my private SSH key, SSH password, my username, and the server’s IP address. Now I can drag and drop files into the server without touching the terminal.

I also added a few conveniences:

  • I set Cyberduck to go into /var/www/htdocs/ every time I connected to my server.
  • I added the URL of my server so that I could right click and copy the URL of any file.
A screenshot of my settings on Cyberduck showing the preferred path and web URL options.

And we’re done! Now I can send files and even host little “pens” for demos.


I ended up going with Tresorit instead since I already use that service for backups. It’s just cheaper to use that service for file sharing as well.

Tiny Generative Art Template

A screenshot of Windows Terminal that shows the directory structure of the project.

I’ve been using canvas-sketch ever since I started learning generative art back in November. It’s an incredibly useful tool for creating a new project, setting up a local server, and saving my artwork to disk. The only issue that I have with it is that it comes with a lot of dependencies that I don’t think are necessary for the kind of art that I do.

So I thought that I could take a stab at creating a minimal generative art template that only includes the things that I need. This is is how it works:

Screencast showing a demo of the project. You can try it out yourself here: ~jagtalon/generative-art-template

It’s not a zero-dependency template, but as long as you have CoffeeScript and Browsersync installed, you should be good to go. To start a new project, all you need to do is:

  1. Download or clone the template.
  2. Run ./ (runs the CoffeeScript compiler)
  3. Run ./ (runs the Browsersync server)

And you’re good to go! The two most important files in it are index.html and

  • 💻 index.html is a barebones HTML file that lets me view and save the artwork. It has a little bit of CSS that makes the Canvas responsive (I often work with large 3600×5400 images!) and a little bit of JavaScript that lets me download the art.
  • 🎨 is where I draw. It’s written in CoffeeScript, and it’s compiled to JS. I’m using it as a JavaScript module so that I can easily import libraries that are both local (like my little Canvas API wrapper called and remote (like NPM modules on Skypack).
Screencast showing how short the index.html and files are.

And that’s it! and are set up to watch the files for any changes, so there’s no reloading involved once these two are running.

Of course, I could get really lean by removing the dependency on CoffeeScript, but I personally enjoy working with this language so I decided to include it. If you’re interested in tweaking the setup, feel free to fork the project and modify the template to your needs! You can find the repository on Sourcehut.

Hello, Tarsnap

A screenshot of Windows Terminal showing the Tarsnap command outputting the size of my backups.

I was put off by Tarsnap Backup when I ran into it many years ago. I liked that it’s trusted and secure enough to be used by companies like Stripe, but I just didn’t want to put in the work to modify configuration files, write shell scripts, and set up cron jobs to backup my files. That felt like too much effort for me to manage. I have a laptop, not a server.

But over time, my backups have become a bit of a fragmented mess. I ended up adopting multiple services (and overpaying for storage) because they were easy and tightly integrated with my devices. I have iCloud for my photos, OneDrive for my documents, and Backblaze for everything else on my computer.

I wanted to consolidate everything I had into a single place, and I wanted it to be cheap and secure. Tarsnap came to mind again because it’s inexpensive enough for my needs, and I like that I’d be the only one holding the encryption keys. (It costs $0.25 per GB, so it’s not the cheapest one out there, but deduplication has done wonders for me.)

This is how I have it set up on Windows through WSL.

Specific directories

I don’t want it to make a backup of my whole drive because that will take forever to upload on my 5Mbps network. Even though Tarsnap is affordable, it could get expensive if I backup unnecessary program files.

So in this script, I created a variable called $directories in the backup script that lists out the folders I care about in both Windows and Linux.


set directories "/mnt/c/Users/jag/Documents" "/mnt/c/Users/jag/Desktop" "/home/jag"

/usr/bin/tarsnap -v -c -f (uname -n)"-"(date +%Y-%m-%d_%H-%M-%S) \

Backup Intervals

I want the backup to run automatically in the background, so I had to set a cronjob. I typed in crontab -e and set Tarsnap to run every half hour (4pm, 4:30pm, 5pm, etc.)

*/30 * * * * /home/jag/

I haven’t run into this, but I’ve read that cron can fail silently. So I had Dead Man’s Snitch set up as well to warn me if my cronjob didn’t run in the last 24hrs just to be extra safe. They have a program called a Field Agent that monitors execution time and output of the backup script.

*/30 * * * * /home/jag/dms -s 012345 /home/jag/
This is my dashboard on Dead Man’s Snitch. It’s free when you’re only monitoring one cronjob.

Cron in the background

This part gets pretty hacky. The problem is that the cron service doesn’t start automatically in WSL 2. Even though I have cron configured, it’s not going to execute unless the cron service runs in the background. Not having a normal boot process means that services in Linux have to be started manually, but I didn’t want to run the backup myself every time I boot up! I’d have to run the following manually:

  • Open Windows Terminal
  • Start Windows Subsystem for Linux by typing wsl or ubuntu
  • Run sudo /etc/init.d/cron start
  • Type in my password

I needed to make all these steps automatic. First, I removed the need to put it in a password when running cron by adding this to the sudoers file (which you can get to by typing in sudo visudo):

jag ALL=ALL NOPASSWD:/etc/init.d/cron start, /etc/init.d/cron status

Now that I can start cron without a password, I can get it to run in the background without a password prompt when I log in to WSL. I added this condition to (The .bashrc on Fish Shell):

# Start cron if it's not running.

if sudo /etc/init.d/cron status | grep 'is not running'
    sudo /etc/init.d/cron start

Now that I’m able to start cron automatically, all I needed to do is to run WSL when I log in on Windows. Pressing Win+R and typing in shell:startup took me to the startup folder. In it, I wrote wsl.bat that just had ubuntu.exe in it.

Easier Tarsnap commands

I have trouble remembering Tarsnap commands, so I made some aliases to make it simpler for me. I wrote this function in ~/.config/fish/functions/

function tarsnap
    switch $argv[1]
    case stats
        command tarsnap --print-stats --humanize
    case archives
        command tarsnap --list-archives | sort | tail
    case extract
        command tarsnap -xf $argv[2..-1]
    case ls
        command tarsnap -tf $argv[2..-1]
    case '*'
        command tarsnap $argv

This means that I could just type in tarsnap stats instead of tarsnap --print-stats --humanize and tarsnap archives instead of tarsnap --list-archives | sort | tail. Much easier to work with!

Running tarsnap stats and tarsnap archives.

Was it worth it?

That was quite a bit of work to figure out and set upespecially on Windows! There should be fewer (and less hacky) steps on macOS or Linux, but I’m glad that it’s all running smoothly for me. There’s nothing else for me to do aside from making sure that it’s running. It should also be easier to set up in a new machine now that I know how to get it to work.

So was it worth it? I think it is. The reason I did this in the first place was that Tarsnap was affordable and more secure than anything I’ve used before, so I think I still come out ahead even after all that work. We’ll see if I change backup preferences in the future, but for now I think I’m content with what I have.

Creative Coding: Setting Up on Windows

A screenshot showing Windows Terminal

The Canvas and WebGL workshop that I’m taking right now is taught using macOS, so the course assumes that I can access some Unix tools and commands in the dev environment. Since Windows isn’t built on top of BSD or Linux, I have to do a bit more work to get up and running.

Install Windows Subsystem for Linux

Windows Subsystem for Linux or WSL is the best way to get a Linux environment running on Windows. It’s a lightweight virtual machine that runs unmodified Linux binaries on top of Windows. It’s so fast that it doesn’t feel like I’m using a VM at all.

See how quickly WSL boots up. It’s magic.

There are two versions of WSL, so I made sure to get WSL 2 because it’s 2-5x faster when it comes to IO operations like git clone and npm install—commands that I’ll often be using!

Install Remote – WSL Extension on VSCode

The Remote – WSL extension on VSCode forces all the commands to run in the Linux VM. It makes sure that I’m interacting with Linux all the time while I’m in VSCode. So even though the editor is running on Windows, programs like Git or Node are all running in Linux.

VSCode with the Remote – WSL extension.

Bonus: Install Windows Terminal

I’m a fan of good-looking terminals, and the built-in terminal on macOS is beautiful. It looks modern, and it supports tabs and theme customization. The built-in Command Prompt on Windows, on the other hand, looks quite ancient.

Fortunately, Windows Terminal is available in the Microsoft Store, and it supports tabs, vertical splitting, and even emojis. I don’t know why this isn’t included in the OS in the first place!

Windows Terminal with vertical splitting.