If you’ve listened to recent Friends with Brews episodes, you probably know that I’ve gotten into Raycast in a big way. Raycast falls in the category of “App Launcher”, but I really dislike that title as it sells short what most of the good app launcher category apps do. For me, Raycast is a system utility that verges into automation territory.
I intended to write one blog post about all the features I use in Raycast. About the time I’d gotten to the 1600 word mark on my draft, I had a conversation with my friend Peter about some Raycast articles he’d read. Specifically, Peter didn’t like the fact that they all mentioned some commands you could use and showed some screen shots, but never went into depth about how they worked or why you’d want to use those features to begin with. At that point I saw my single gigantic post fracture into a million tiny pieces, and I knew it was going to be a series on Raycast. It’s the only way to provide meaningful information on how to use it rather than just flinging a bunch of bullet points at the page.
Raycast has a lot of features and requires some digging into to find what works and how it works. The versatility in terms of how to find and use commands is important to grasp because the right setup can make the difference between adding new workflows to your Mac use that make you efficient and happy, and forgetting those features are there at all and wondering why people think Raycast is even useful. It’s no different than any other multipurpose tool in that regard.
What IS Raycast?
What does Raycast say Raycast is?
One way to find out what an app is is to ask the developer of the app what it is. Raycast (the company) has this to say about Raycast (the product):
Raycast is a blazingly fast, totally extendable launcher. It lets you complete tasks, calculate, share common links, and much more.
That’s great, and it’s true, but it’s also not enough information to help someone who truly doesn’t know anything about the horrendously named app launcher category understand why they’d want to use it. I understand they need a concise statement of purpose, and truthfully I doubt I could do any better myself. That’s why this first blog post in my series on Raycast is just bit longer than that.
What does ChatGPT say Raycast is?
I decided to ask ChatGPT, via Raycast, what ChatGPT thinks Raycast is. ChatGPT’s reply?
Raycast is an AI-powered software productivity tool that provides a unified interface for accessing and executing various tasks, applications, and information within a computer’s operating system. It allows users to quickly search for files, launch applications, perform calculations, access web services, and more, using a text-based command bar. Raycast aims to streamline workflows and improve productivity by simplifying task execution and information retrieval within the computer environment.
Ok. Again, all technically true, and it’s definitely “within the computer environment”, which is good to know if you’re worried about Raycast trying to take over your house or steal your car.
What does Scott say Raycast is?
Raycast is a Mac power-user utility for making your workflows faster, more powerful, and more centralized and maintainable.
That’s basically my way of saying if you really want to know what Raycast is, you’ll have to read this series. 🙂 But let’s cover some basics and key features of Raycast that will help as I slowly roll out blog posts emphasizing a specific command or extension in detail over the course of this probably infinite Raycast series.
Some Basics
Raycast is categorized as an app launcher. To that end, it’s basically a search bar that appears on screen when triggered by some key combination. Personally, I use Opt-Space, although I could map it to Cmd-Space and completely replace Spotlight’s keyboard shortcut.
Search and Selection
Once the search bar appears, you start typing things, varying depending on your goal. If you want to launch an app like the horrible category name suggests, you start typing the name of the app and Raycast comes up with options for you to choose from.
To make selection fast and easy, Raycast lets you use Cmd+number keyboard combinations to make a choice. Hold Cmd for a second and you’ll see what number key to hit to select a particular option. They’re numbered from top to bottom as could be expected, so the Cmd+number choice for a given app is just its order in the list.
This same Cmd+number selection technique works for anything you search for in Raycast, so anytime a list is on screen, you can use this to quickly make your choice from the list of applicable items.
HotKeys let you perform a command without having to open Raycast first. This works especially well for its window management commands, but is useful for a lot of things.
Aliases require you to open Raycast, but then you just quickly type the alias and you have that command selected and ready to execute without having to search for it and choose it from the list.
Here’s an example of a bunch of the Window Management commands with HotKeys assigned, followed by one of some Safari commands with Aliases.
These are some of the very basics of Raycast that will come in handy as I show some examples of my Raycast workflows in future articles.
To Be Continued
I already have some posts on other topics that could be linked as different series on my site but I currently have no way of grouping them and surfacing them to the user as a series. Adding that functionality to the site will be step 1 in the Raycast series, even before firing up Drafts and typing additional words about the app itself. It should be easy enough, and I can even write about how I did it. Bonus!
Once that’s done, Raycast deep-dives will be forthcoming.
As I wrote yesterday, I celebrated John Siracusa’s every-five-year Hypercritical t-shirt sale with a new Hypercritical Gold Theme for this site. As with my previous dark/light mode configuration, toggling themes is done with a little icon button at the bottom of the menu that can look like a sun (when in light mode), a moon (when in dark mode), and now a 128k Mac (when in Hypercritical Gold mode).
Theme toggling can cause flickering issues when pages load. The symptom is that when you click a link to go to another page on the site, you see a flash of the wrong colors and then the page quickly switches to your chosen theme colors. This is because when the default colors load first, and then the browser realizes you’ve set the theme to something else and loads the correct colors. I had this issue myself, but I didn’t really notice it when I just had light/dark modes, probably because I was almost always in dark mode. I did notice it right away when I added Hypercritical Gold.
I found two articles addressing this issue, one of which was even written from an Astro perspective.
They both basically use exactly the same technique – early on in the page, either in the <head> section or early in the <body> section, have an inline JavaScript that checks your preferred theme setting by seeing what your localStorage setting for your theme choice is.
As it happens, I was already doing this. But I was doing it in my menu component, which in turn is called by my Base.astro base layout. Also my script was declared as <script> instead of <script is:inline>, which in Astro means it was getting bundled by Vite instead of loading directly inline where it was declared. The result of these two factors meant the timing of the script checking the visitor’s theme preference was off, and theme flicker was the result.
My first attempt at getting rid of theme flicker was changing the script to use the is:inline directive, but this caused a problem. Now the script couldn’t find the elements it referred to by ID, namely the theme toggle icons. My assumption is this is because Astro was modifying the element names as part of how it bundled up and rendered the component, but with the JavaScript now being unmodified and unprocessed by Astro, it no longer knew what those were now called.
Because of this, I decided to nuke the menu component and move everything in it into Base.astro. I moved it as is, with the JavaScript above the html for the menu elements, and the script using the is:inline directive. Now I had a new variation of the JavaScript can’t find html elements issue. For fun, I tried moving the JavaScript down below the menu html, hoping it was still high enough in the page to load the theme quick enough to avoid theme flicker. It seems to have worked – I don’t see theme flicker now while using Hypercritical Gold or Light themes. These are the two themes that would show flicker, because Dark theme is the default.
To recap, I no longer have a Menu.astro component. My menu is now in my Base.astro template. The highlighted part is the JavaScript dealing with loading the correct theme based on the user’s preference, and changing themes when the toggle icon is clicked or tapped.
The moral of the story is, grab the user theme preference and set the theme early in the page load lifecycle. With Astro, that means understanding how Astro is optimizing your layouts, components, CSS, and scripts.
In my case, because the JavaScript is loaded above the part of the base template that loads the page content, it seems to work timing-wise to load the theme quickly enough to avoid theme flicker.
You can toggle the themes on the site menu. There’s a little icon under all the menu items that appears as a moon (if you are in dark theme), a sun (if you’re in light theme), or a little 128k Mac (if you’re in hypercritical theme). Clicking that icon toggles through the themes from dark to hypercritical to light.
You’ve seen a lot of code blocks on this site in various posts of mine, primarily because I’m not ashamed to show what a bad programmer I am or how excited I am that I learned something that’s probably rudimentary to many people. And while I like how the native Astro support for the Shiki syntax highlighter works, I really like how code blocks look in Astro’s documentation pages even more. It looks like this:
I like the way they do this because it supports various languages and syntaxes, it allows for a frame with the name of the file being shown if applicable, and in general, it just looks really good.
I posted in the Astro Discord Starlight channel to ask how they tweaked Shiki to make it look like this, because I couldn’t tell from the Starlight source. I was looking for rehype markdown plugins or something. Chris Swithinbank, who’s a huge Astro docs contributor and also contributor of code for the Astro docs application itself, replied to let me know that what they’re doing for code blocks in the Astro docs is even simpler than that – it’s called Expressive Code.
Expressive Code is really all about code blocks, or syntax highlighting. And it just so happens most or all of the contributors are Astro contributors (including Chris!). This is great news because one of the packages available in Expressive Code is astro-expressive-code, which is an Astro specific Expressive Code integration. It’s so easy that all you have to do is install that one package in your Astro site and you’re in business.
I installed it using the Astro CLI as recommended in the astro-expressive-code README with the command npx astro add astro-expressive-code (since I’m using npm). After that, I did absolutely nothing except edit all my posts with code blocks to add titles to any code blocks that I wanted to list file names for. Now my code blocks look like this:
Right now I’m just using the default Shiki GitHub theme. I haven’t customized the look at all. While they do look fine as is, I will customize the look more when I have time.
One of my site to-do items for a while now has been doing something with the keywords I add to each post’s front matter. Content in Astro can be different variations of Markdown, and front matter is a YAML section with metadata about the content, such as title, description, publish date, or really whatever you want to put in there. One of the things I add there is a YAML array of keywords which are really just tags. I called them keywords, they could have been called categories, tags, topics, whatever.
Here’s the YAML front matter for my last post, which was about podcasting software:
I thought it might be nice to add the ability to view posts associated with specific tags, to add a post-filtering option in addition to the site search. That way people could see everything I associated with “mac” or “podcast”, for example. I decided to show a subset of tags on my home page and have a tags index page that listed all of them. The tags in those tag lists would link to the specific tag’s page, with a list of posts using that tag.
Thanks to others who are a lot smarter than me who’ve already done this very thing with Astro, finding excellent examples to borrow and steal from didn’t take long at all.
I did a search for “astro tags” and found that the Astro documentation site has a tutorial that covers building a tag index page as well as individual tag pages, but I wanted some better examples of pulling the tags from the posts and sorting and filtering them rather than the array of tag objects used in the documentation examples.
Sarah’s post does a great job of explaining static vs. dynamic routing, and the astro getStaticPaths() function that’s used to generate dynamic routes. First, though, she builds her src/pages/tags/index.astro page which serves as her tags list page (which you can see in action here).
I have a slightly different approach in that I use Astro Content Collections, which were introduced after Sarah’s blog post, rather than Astro.fetchContent(), which she uses, which was in turn deprecated in favor of Astro.glob() in Astro 2.0. For now, just think of Content Collections as another way of grabbing all associated documents, such as posts. You can still use Astro.glob(). Content Collections have a few benefits that glob doesn’t, but require a little extra setup.
In any event, I wound up with this for a tags index page:
Well, that’s not very exciting. I don’t do any of the cool post grabbing stuff that Sarah does here. That’s because I put all that work into an Astro component I call TagCloud. You can see that I use my TagCloud component there in my tags index page. I did this because I also wanted to show a subset of my tag cloud on my home page and on my search page. Creating an Astro component to actually display the tag cloud makes all that logic and display markup reusable.
Also note that I pass two params to my TagCloud component – showCount="true" and displayNumber="999". I’ll explain those pretty soon.
HERE is where the magic happens, in TagCloud.astro itself:
Ok, that’s kind of a big chunk of code, but a lot of it is html and styling. But there are a few important parts, namely all that JavaScript in the front matter regarding allPosts, allTags, processedTags, and sortedTags.
Basically what this does is get my posts Content Collection, get the keywords arrays from the front matter, and then create a JavaScript object of key value pairs with each tag I’ve ever used as a key, and how many times I’ve used it as its value.
If you console.log(sortedTags), it looks like this:
You may be wondering why Sarah’s tags index page creates its array of tags very
simply with this:
And why I’m making it super complex with this:
The reason is that I’m keeping count of how many times each tag is used and I’m displaying that in my tag cloud, as shown below.
That’s the only reason why instead of just sticking with a simple array of tags, I am creating a JavaScript Object of key value pairs, with the tag name being the key and the number of times its used being the value.
I am not clever enough nor good enough with JavaScript to have written that function. All of that JavaScript in that code block above is the work of Chris Pennington, who has a really great YouTube channel called Coding in Public. One of his videos is titled Astro Blog Course #12 - Tag cloud, and it’s about exactly what you think it’s about.
My whole TagCloud.astro component aside from styling comes straight from his CategoryCloud.astro component, with one minor change.
My minor change is the addition of a prop called displayNumber. If I give it something real, like 11, it will display 11 tags plus a “All tags… ” link to the tags index page. If I give it 999, it shows all tags. On my tags index page, I call TagCloud.astro with displayNumber="999", while on my site home page and my site search page, I call TagCloud.astro with displayNumber="11". The result is that my tags index page looks like the picture immediately above, while my home page and search page tag clouds look like the following two images.
Individual Tag Pages
The tag pages for individual tags are where dynamic routing comes in. While the tags index page is at src/pages/tags/index.astro, the fact that the individual tag page are dynamically created is evident by the Astro page name: src/pages/tags/[tag].astro. The brackets around the name indicate a dynamic route page, one that generates an actual page for each item in an array of objects. In our case, our objects are tags.
As the Astro documentation on dynamic routes says,
Because all routes must be determined at build time, a dynamic route must export a getStaticPaths() that returns an array of objects with a params property. Each of these objects will generate a corresponding route.
My tag.astro page looks just like Sarah’s as far as my getStaticPaths() function, because hers is perfect. Like I said, people much smarter than me have already solved this problem and documented it for others. I’m glad too, because JavaScript isn’t really something I spend hours improving my skills at. I tend to learn enough to do what I need to and then move on. Unfortunately this means that correctly expressing things in JavaScript like mapping and filtering is sometimes a struggle for me.
Here’s [tag].astro. It’s another long code block but here’s the full code dump anyway.
All of that in [tag].astro equates to the following individual tag view.
I don’t know if you’re tired of tags yet, but I’m getting there. I do like how this turned out though. I think it looks pretty good considering my horrific lack of design skills, and I like how I can implement the partial cloud on the home page and the search page, and the full tag cloud on the tags index page, all from the same TagCloud.astro component.
404, Scott Not Found
Oh, I also added the tag cloud along with a search field on my 404 page too.
And now I’m going to sleep, because it’s after 2 AM and I really need to be 404 myself right now.
I’ve talked about the hardware I use for podcasting, but what about the other tools of the trade? Obviously the first step to creating a podcast is to record one, and in my case, that’s all about software.
The Company You Keep
If there’s one name podcasters who use Macs tend to be very familiar with, it’s Rogue Amoeba. I don’t know if Rogue Amoeba set out to be the go-to people for podcasting on the Mac, but they’ve certainly achieved it. For me, all of their software is indispensable, but there’s one application in particular that you pretty much have to have – Audio Hijack.
Audio Hijack
Audio Hijack bills itself as the “Record Any Audio” application, and that’s exactly what it is. If there’s an app on your Mac that makes noise, Audio Hijack can record it.1
The beauty of Audio Hijack is that it sets up audio recording chains that can include effects, noise removal, peak limiting, and more, and it allows for granular control over whether audio sources get combined into a track or each record their own separate tracks. Each specific setup like this can be saved as a session, so you can always have a session appropriate to whatever kind of recording you want to do.
This session records my mic, which comes in through an Elgato Wave XLR interface, increases the volume, denoises, and ramps down the treble a little bit, because I have a nasally voice.
It also records my soundboard, which is provided courtesy of another Rogue Amoeba app called Farrago, and saves that to its own track.
Finally, it records whatever VOIP app I’m using for the podcast as a backup recording of my co-host(s). Peter and I use FaceTime to talk to each other for Friends with Brews, unless our friend Adam Bell is on, and then we use Zoom.
The VOIP call recording is strictly a backup. We each record our own end locally for the best sound and I combine those tracks in my editor, a process I’ll describe in a separate post sometime soon.
Audio Hijack is very versatile in terms of output file format and quality, and also in terms of file naming.
As I mentioned, you can save recording configurations as sessions. Here are all of my currently saved Audio Hijack sessions for recording various podcasts and Mac apps. Episode 18 of Friends with Brews wasn’t really the last time Adam was on the podcast and we used zoom (it was episode 39, I think) but apparently I forgot to rename that session. Anyway, you get the idea.
Farrago
I mentioned Farrago earlier. Farrago is an amazing soundboard application that lets you store, perform minor edits on, and trigger audio sound clips – in other words, it’s a soundboard!
Farrago is how I play the “Friends? With BREWS?!” clip at the beginning of every podcast, as well as the “Hi, Peter!” and other clips that I like to annoy people with during various podcasts. I have a TON of Farrago sets with sounds from all kinds of stuff.
Vic Hudson and I used to do tv show related podcasts for BubbleSort TV, and those sound clips came in super handy. We’d usually set up sections of the podcast by playing clips from specific scenes, which really added to the shows. It also means they’re inserted live into the recordings (although we made sure they were on their own tracks for easier audio leveling and editing reasons) so they wouldn’t have to be edited in later, AND so the co-host could hear them and we’d both be on the same page about the conversation to follow.
By the way, if you guessed that I recorded every single one of those tv show and movie clips using Audio Hijack, you’re correct!
Loopback
“But Scott!” you say. “Just because you’re playing a sound clip in Farrago on your Mac doesn’t mean your cohosts can automatically hear them, does it?!?” Great question. The answer is no. No, it does not. Enter Loopback.
Because you’re such a doggone great guesser, maybe you surmised that Loopback is Yet. Another. App. By. Rogue Amoeba.
YES! IT IS! And it’s amazing, so back off! It’s not my fault they make all the best podcasting and audio routing and recording related software for the Mac!
Loopback does a lot of things, but simply put, it lets you combine audio sources into one or to pass audio from one application to another. The first use case is how my co-hosts can hear my soundboard – I have a Loopback device that combines my mic with Farrago. I can then set THAT as the input to my VOIP app of choice, such as FaceTime or Zoom or Skype, and then everyone on the other end(s) of the call can hear my soundboard coming from me exactly the same as they can hear me talking.
This Loopback device looks a lot like this – in fact, exactly like this:
Usually, even though each app can have its own inputs and outputs separate from the system settings, I just set my system settings to the output I want (my Elgato Wave XLR, which my podcasting headphones are plugged into) and the input that I want (my Loopback input source that combines my mic and Farrago).
Then I set my VOIP app de jour to use system settings for input and output.
And, So
And THAT, my friends, is over 1000 words on software that I use to record the podcast. It’s not complete, because I have a few helper utilities that prepare the way, as John Siracusa might say, but I’ll save those for another post.
So topics you have to look forward to in this series in the future are helper utility apps that prepare the way for recording, apps I use during the editing process, what exactly my editing process actually entails, and finally, how I get all that published and ready for YOU to listen to, in the case of Friends with Brews especially.
You can bet on it. But maybe you shouldn’t. Just saying. Never bet unless the outcome is already certain. And then always only bet a dollar.
Footnotes
It can actually even record apps that don’t make noise, but that’s probably an exercise best reserved for the metaphysicians of the world. ↩
Thanks entirely to Tiffany White, I finally implemented something that’s been on my site to-do list for some time, but that I’ve never gotten around to actually doing until now: link posts.
You’ve seen link posts before, certainly so if you read a lot of Mac related blogs like Daring Fireball, SixColors, or MacStories. The idea is the title of the post links to an article on another site, and then you add some commentary and maybe quote part of the article in your post.
Tiffany created an issue on my site repo asking if I’d setup link post support in Astro yet. I had it on my to-do list, namely in my Obsidian kanban board for this site, but I hadn’t done it yet because I haven’t really wanted to link to too many external articles here. But Tiffany creating an issue for me gave me the motivation to figure out how I would do it.
Adding the Url Link
In order to add the URL that the post title should link to, I decided to add a front matter item called link:
Adding the Link to the Collection Schema
Because I’m using Astro Content Collections, I also needed to add this to my collection schema. Not all posts will have a link front matter item, so it needs to be optional.
Zod allows for optional entries, so links is defined as a z.string().optional().
The Astro Code for Link Post Titles
The rest of the work is done in a new component for creating the blog post title called PostTitle.astro.
I check for the existence of the link front matter value in two places: one for creating the href for the post title, and the other to decide whether or not to show the link icon next to the post title indicating that this is a link post.
If post.data.link exists, I use that as the href for the title link, otherwise I use the url of my blog post as the href so that my blog post links to itself as usual.
Now in my Post.astro component which creates the blog post layout, I call my PostTitle component instead of just creating the title in Post.astro itself.
This is the result:
Before implementing PostTitle to create link post titles when appropriate, I just created the title directly in Post.astro with the following:
As you can see, it’s just a subset of what’s now in PostTitle.astro, namely just the portion that assumes the post title should just link back to the post itself. But you can see how easy it was to go from that to the new PostTitle component that can handle both link posts and regular posts.
Improvements
That’s it! There are still some improvements to be made. Besides just showing the link icon next to the title of a link post, I probably want to change the color of the title slightly and maybe change the post background color very subtly to indicate that it’s not just the usual site post.
I also plan to make quote sections a little more stylish by adding some nice quote marks around them to offset them just a little bit more than they already are.