Category: #Coding

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.

💬 hi@jagtalon.com

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])

💬 hi@jagtalon.com

I made a zine in HyperCard

I wanted to create an interactive thing where the player can play as a villain — in this case a surveillance capitalist. I thought HyperCard would be a perfect medium because it has built-in programming and art tools. Plus, it’s fun running old software!

Drawings are all my own except for the little Macintosh illustration. That came with HyperCard.

I followed the instructions on https://cancel.fm/hyperjam/ when I set it up on my computer, but if you want to run it yourself, https://system7.app/ should be the easiest way to do it!

This work was inspired by:

Budgie Released

I might be the last person on Earth to realize this, but I recently learned how useful spreadsheets can be in my personal life. This whole time I’ve been avoiding spreadsheets because I thought they were for serious business people who need to do serious things like projections and reports.

So I’ve been pushing myself to learn Excel recently, and I’m amazed how quickly I can make “apps” for myself through Excel vs doing it in a proper programming language. I’ve been proud of a minimalist budgeting system that I made that’s inspired by YNAB called Budgie, so it’s up online if you’d like to use it!

Caps Warlock and Alarm Pup Released

I recently released two new apps on itch.io: Caps Warlock and Alarm Pup.

Caps Warlock is an AutoHotkey script that I’ve been working on to make the Caps Lock key more useful. It adds useful keyboard shortcuts to desktop apps like Figma, Firefox, and Sublime Text. It doesn’t support that many apps yet, but I’m slowly adding features to it.

Alarm Pup is a countdown timer that I worked on during the holidays to help me take breaks and timebox tasks during the workday.

Try it out! I hope you find it useful.

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 itch.io app.

Head on over to itch.io 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
XButton1::h

; Move Tool
; Trigger: 5th mouse button
XButton2::v

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
WheelLeft::^+Tab
WheelRight::^Tab

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
^f::
FigmaPlugin("find and replace")
return

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).

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 ./build.sh (runs the CoffeeScript compiler)
  3. Run ./server.sh (runs the Browsersync server)

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

  • 💻 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.
  • 🎨 art.coffee 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 tiny-canvas.coffee) and remote (like NPM modules on Skypack).
Screencast showing how short the index.html and art.coffee files are.

And that’s it! build.sh and server.sh 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.

Long-Exposure Art

A photo of my night sky art on my table. There's also a toy dog beside it for scale.

I’ve been fascinated with long-exposure shots of the night sky recently (like this one), so I thought it would be fun to emulate that effect on <canvas>. I assumed that it would take me a while to figure it out, but the algorithm turned out to be surprisingly simple!

The first thing I noticed was that each “star trail” is basically a small segment of a circle, so I figured that I’d be using the arc() method a lot. After staring at different long-exposure photos, I also noticed that the star trails grow in length as it moves farther away from the center of the spiral. This told me that the angle that I’ll use for the arc will probably be constant throughout the artwork. The only thing that needed to change was the radius of that arc.

But how do I draw multiple arcs across the canvas? My first solution was to generate random x-y coordinates all over the page and then get the distance between (0, 0) and (x, y) using Math.hypot(). I then created an arc for each point using the distance as its radius and then spun it around to a random angle using rotate(). It looked something like this in CoffeeScript:

# For each point:
# 1. Find the distance between (0,0) and (x,y)
# 2. Create an arc with constant theta
# 3. Rotate it to a random angle (Math.random() * 2π)
drawStarTrails = (x, y) ->
    context.arc 0, 0, Math.hypot(x, y), 0, theta
    ...
    context.rotate Math.random() * 2 * Math.PI

# Draw random x-y coordinates
drawStarTrails(Math.random() * width, Math.random() * height) for n in [1..1000]

But then I realized that I didn’t need to find the distance between (0, 0) and a random point at all. I could just plug in a random radius and I’d get the same effect:

# For each iteration:
# 1. Find a random radius.
# 2. Create an arc with constant theta
# 2. Rotate it to a random angle (Math.random() * 2π)
drawStarTrails = () ->
    context.arc 0, 0, Math.random() * width, 0, theta
    ...
    context.rotate Math.random() * 2 * Math.PI

# Create the star trails
drawStarTrails() for n in [1..1000]

And that was it! Now it took me a couple of hours fiddling with different colors, gradients, angles, stroke widths, and the number of arcs to get it to look right (the final version has 9000 arcs!), but this project reminded me how simple rules could generate something that looks complex. It’s honestly one of my favorite things about generative art.

You can find the complete source code on Sourcehut. You can also get prints in digital and physical formats (if it’s in stock) here 🖼.

This is the final version of the artwork. You can find the source code here if you’d like to read the whole program or make modifications yourself.

Two Posters of Space

A print of my art of a spiral on top of my keyboard.

I recently made two space-themed posters, and I think they turned out pretty nicely! The first one that I made was honestly a bit of an accident. My initial goal was to create a sunflower, so I watched some YouTube videos on how spirals work, and I also read some code online to learn how they’re implemented as a program.

But as I played around with different spiral styles and backgrounds, I decided that it was better to go with this galaxy/wormhole poster instead.

I was really happy with how this poster came out, so I thought it would be fun to continue working on space art. A planet felt like a good next step, so I made this gas giant poster next. The planet itself is a circle with a gradient fill, and the rings are ellipses with a gradient stroke.

A green-blue gas giant floating in a sea of stars. You can find the code here.

It’s a pretty simple illustration, but I think the fun part was implementing this in Lisp. I used Lisp instead of JavaScript this time because I wanted to try out this experimental image processing tool called Ronin. I don’t have much experience programming in Lisp, but it felt perfect for generative art. It didn’t look as verbose or as cryptic when compared to using the Canvas API directly. If I wanted to draw a star, I could simply write:

(fill
    (circle x y radius) "#DEE2E6")

Instead of:

context.fillStyle = "#DEE2E6";
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, true);
context.fill();
My desktop while working on Ronin. Half of the screen is used by Ronin itself, while the other half is used by tutorials and documentation.

There’s something fascinating about creating art by simply specifying a set of rules for the computer. There are so many possibilities! I’m hoping that I’ll continue exploring generative art for the years to come. I’ve been collecting my favorite works in https://jagtalon.com/generative-art/ as well so check that out from time to time if you’re interested!