Screencasting Secrets

Screencasting is my secret weapon as a remote software engineer. I'm one of those people who just wants to go fast all the time, and you get to move a lot faster once you get good at showing people what you've made and putting them at ease about the idea of shipping it. At any job, one of the most common questions I hear is "How do you do all those GIFs and videos and screenshots and stuff?". Here's how.

Text is first

Working well with plain old text is a prerequisite for any kind of screencasting success. Deep down it's the same thing: you're trying to get information from your head into someone else's. If your written communication isn't clear, your screen recordings won't be either.

Think about how you report bugs, for example. The phrase "it's broken" might mean anything from "it's crashing on startup for 100% of users" to "I don't feel like the performance is reliable enough". The phrase "the numbers are wrong" might mean something as severe as "these miscalculations will get us sued by the tax authorities" or as minor as "we're showing too many decimal places here". If your text communication style is vague, your screenshots and screen recordings will probably be vague too.

The trick with the bug report example is to think about what your expectations were, contrast them with what actually happened, and write something that conveys the difference between the two as clearly as possible. It's a thought process that requires you to put yourself in the shoes of the audience and take the time to shape the message around their perspective. Half the ingredients of success when producing a video or screenshot of something is applying that same thought process in a visual way.

Screenshots

The simplest thing to share is often a screenshot. If something can be conveyed in a static image, it's almost always preferable to do so rather than deal with the extra headaches that come with video. The principles of taking good screenshots, such as tailoring the framing and sizing to suit the target platform and audience, are fundamental to good screen recordings too.

You can take a screenshot of your entire desktop by pressing โŒ˜โ‡ง3. That's usually the wrong option though. It's almost always better to use โŒ˜โ‡ง4 and then select a region using the mouse. Another great option is to press โŒ˜โ‡ง4, then space, and then click on a window to take a screenshot of it. In the following video, I'll demo all three of these, in the same order as they're written.

I'm using Keystroke Pro in the video above to visualise the key presses. It's a tool I recommend very highly. It comes in especially handy if you need to screencast a series of keyboard interactions like this one.

Even the humble screenshot has some nuances that are worth thinking about. Where will you upload your screenshot and how much space is available for it there? What size is optimal to help your audience understand your point as easily as possible? If there are multiple windows involved, is there some way you can rearrange them to structure the information in the screenshot more clearly?

If you're posting something on a GitHub issue or pull request, for example, you'll have about 800px of width to play with. Could it work for you to resize the window in preparation for your screenshot so that it doesn't appear too zoomed out and squished there? For before/after screenshots, it fits particularly well if both screenshots are a common mobile resolution.

Annotated screenshots

Sometimes your screenshots need a little extra something. Like occasionally it's just easier to visually highlight some detail in there with an annotation. For this, I use Skitch.

Awkwardly, Evernote acquired Skitch back in 2011, and in recent years it's basically become abandonware. But for now at least, you can still do brew install --cask skitch, and it'll run. In theory you can do โŒ˜โ‡ง5 to take screenshots directly into Skitch, but in practice that's been broken for years, so I take them with the macOS native โŒ˜โ‡ง4 and then drag & drop them into Skitch like this.

I'm using the โŒ˜-Space keyboard shortcut here to open Skitch using Spotlight.

It's a shame Skitch is slowly dying. I've been recommending it to colleagues since like 2015, and still occasionally see someone I introduced it to share something annotated with it on social media. Will be sad when that connection is finally broken.

Animated GIF screen recordings

You can get a lot done with screen recordings in animated GIF format. They're incredibly versatile, because almost all chat & collaboration platforms allow you to post GIFs. Gifox is the best app for this, and well worth the cost.

Fear of failure holds people back from trying this. People worry it'll require advanced technical skills. It doesn't. Here's a video of the full end-to-end recording and editing workflow to produce one GIF. It takes less than a minute.

This is what it looks like to create a screencast GIF using Gifox. The app I'm using as an example to record is Boop.

Gifox gives you lots of control over how to export your GIF. The one I use most often is the resizing option, which is why I made sure to demo it in the video above. Big animated GIFs take so long to load that nobody will watch your video, and scaling down is an easy way to avoid this. Most of the time you don't really need a full 100% original size GIF either.

The secret to doing these things right is to keep them short. Animated GIFs almost never have playback controls, so your audience has no way to rewind or pause your video. And longer GIFs will exceed most platforms' upload file size limits anyway.

Another thing to bear in mind is that GIFs loop. Sometimes it's necessary for the clarity of the video that the end point should be very distinctive. Other times it's super nice to make the loop completely seamless. It's a case-by-case thing and you get a feel for it after a while.

Video screen recordings

When something won't fit within the limitations of the GIF format, I'll fire up QuickTime and do a screen recording instead. This has a similar workflow to Gifox. You select an area to record, do your demo, end the recording with the little taskbar stop button, and then press โŒ˜T to trim the clip.

I made all the other videos for this post using this workflow. This one took some fucking doing though.

It's worth checking the options before hitting Record. Pay particular attention to the microphone setting. Most of the time you'll want to set this to None. Nobody needs to hear the background hum of your dishwasher while you demo your new feature or whatever you're recording.

QuickTime will output a fairly chunky .mov file at the end of this. I tend to use ffmpeg to scale these down and convert them to .mp4. This will often cut the file size from tens or hundreds of megabytes down into the 1MB-ish range.

ffmpeg -i words.mov -vf "scale=iw/2:ih/2" words.mp4

Video screen recordings with system audio

When I need to include system audio in a screen recording, I reach for Rogue Amoeba's excellent Loopback app. Nine times out of ten, if I'm doing this it's because I want someone to hear what a screen reader interaction with their UI sounds like. For this, I have a premade VoiceOver virtual device configured in Loopback. It just needs switching on, and then it's available as a microphone in QuickTime's recording options.

This one's complex enough that I figured it's helpful to make the resulting screen recording available so that you can see for yourself that the screen reader announcement audio has been captured in the recording.

For screen reader announcements in particular, it's often overkill to go to these lengths. I've mainly found it useful when working in partnership with blind people to evaluate and improve complex ARIA implementations. For demonstrating screen reader announcement changes to sighted colleagues I've often found it sufficient to show them animated GIFs with VoiceOver's visual announcement visible in the viewport.

Give it a try

You don't need to wait for your employer to approve budget for some expensive 3rd party SaaS screencasting platform like Loom. Fancypants extras โ€“ like enabling you to overlay a video of yourself talking on your screencasts โ€“ might sound like gamechangers. But I think most of the outcome in these techniques depends on whether or not you personally engage with communication as a craft in itself, and you don't necessarily need to add another subscription to your monthly bills if you're willing to learn your way around a handful of standalone tools.

Sighted people bloody love a visual demo, and catering to that preference is an underutilised way to speed up feedback loops and build trust and consensus around shipping things sooner. If you take away nothing else from this, I hope you install Gifox today!

Maining VSCode Terminal

Once upon a time, the main tools I used for work were Vim and tmux. And until recently, once every few months I'd get this compulsive urge to try to recapture those glory days. If you know, you know.. That urge has stopped lately though. Visual Studio Code has reached a tipping point where the Vim support and terminal emulator are a better package than anything I can hack together with lua plugins and tmux config.

Turning VSCode into something that feels cosy for this type of retro workflow preference doesn't even take a lot of configuration. Here's how I'm doing it.

Editor

The editor is basically good to go once you install the Vim plugin and make one or two tweaks. By default, VSCode does a lot of automatic closing of brackets and tags and such. Some people love this. For me it just feels like that Sorcerer's Apprentice scene with the out-of-control magic brooms in Fantasia, so I gotta turn it all off.

"editor.autoClosingBrackets": "never",
"editor.autoClosingDelete": "never",
"editor.autoClosingOvertype": "never",
"editor.autoClosingQuotes": "never",
"html.autoClosingTags": false,
"javascript.autoClosingTags": false,
"typescript.autoClosingTags": false,

That's about it, actually. The rest is handled by extensions.

Terminal

The terminal is where most of the tweaking is necessary. The default setup caters for limited use cases โ€“ stuff like opening it in the morning to run yarn start and then closing it in the evening. If you're using the terminal more like an IDE, it needs a little bit of extra juice.

Colors

VSCode's terminal has this incredible minimum contrast ratio option that I can't live without any more. This option alone might be enough to convince many people to switch from other terminal emulators. Ever used a program in the terminal whose ANSI colors contasted so little with your background color that the text became effectively invisible? Crank up this setting to 4.5 and VSCode will automatically detect and fix that whenever it happens.

"terminal.integrated.minimumContrastRatio": 4.5,

I've been using Solarized for pretty much my whole career, and I love that VSCode ships with it included. It also ships with what I consider to be Solarized's worst flaw: the "bright" version of the palette is a gross soup of grays and oranges. VSCode makes it real easy to patch this though. I tend to just duplicate the regular palette, and then trust the magic of the minimum contrast ratio setting to fix any trouble this causes.

"workbench.colorTheme": "Solarized Dark",
"workbench.colorCustomizations": {
  "gitlens.trailingLineForegroundColor": "#93a1a1",
  "terminal.ansiBrightBlack": "#002b36",
  "terminal.ansiBrightBlue": "#268bd2",
  "terminal.ansiBrightCyan": "#2aa198",
  "terminal.ansiBrightGreen": "#9bb300",
  "terminal.ansiBrightMagenta": "#d33682",
  "terminal.ansiBrightRed": "#dc322f",
  "terminal.ansiBrightWhite": "#fdf6e3",
  "terminal.ansiBrightYellow": "#b58900"
}

Keyboard

The keyboard shortcuts to control the terminals are the other big thing to address. Once you've experienced tmux it's hard to accept the rigidity of just having one little panel you can toggle below the code that requires mouse interactions for half its functionality.

First up is the focus management. I need to be able to toggle focus back and forth between the editor and the terminal easily. The following keybindings.json entries configure โŒ˜โ†“ to focus the terminal and โŒ˜โ†‘ to focus the editor.

{
	"key": "cmd+up",
	"command": "workbench.action.focusActiveEditorGroup",
	"when": "terminalFocus"
},
{
	"key": "cmd+down",
	"command": "workbench.action.terminal.toggleTerminal",
	"when": "!terminalFocus"
}

When I'm working in the terminal, I want common shortcuts like โŒ˜T and โŒ˜W to open and close terminal tabs like they would in iTerm2. In VSCode there are two contexts a terminal can be open in: either the panel, or the editor area. The default keyboard controls for these two contexts are different, and the following keybindings.json entries standardise them across both.

{
  "key": "cmd+t",
  "command": "workbench.action.terminal.newInActiveWorkspace",
  "when": "terminalFocus"
},
{
  "key": "cmd+t",
  "command": "workbench.action.createTerminalEditor",
  "when": "terminalEditorFocus"
},
{
  "key": "cmd+w",
  "command": "workbench.action.terminal.kill",
  "when": "terminalFocus"
},
{
  "key": "cmd+w",
  "command": "workbench.action.terminal.killEditor",
  "when": "terminalEditorFocus"
},

Another quality of life thing is to have ^โ‡ฅ and ^โ‡งโ‡ฅ always mean "focus next tab" and "focus previous tab". When I'm working in the panel with multiple terminal tabs open, I want these combos to switch over seamlessly so that they iterate through terminal tabs instead of editor tabs. The defaults here are a long way from this. This next bit of config makes ^โ‡ฅ and ^โ‡งโ‡ฅ do the right thing no matter what's focused.

{
  "key": "ctrl+tab",
  "command": "workbench.action.nextEditor"
},
{
  "key": "ctrl+shift+tab",
  "command": "workbench.action.previousEditor"
},
{
  "key": "ctrl+tab",
  "when": "terminalFocus",
  "command": "workbench.action.terminal.focusNext"
},
{
  "key": "ctrl+shift+tab",
  "when": "terminalFocus",
  "command": "workbench.action.terminal.focusPrevious"
},
{
  "key": "ctrl+tab",
  "when": "terminalEditorFocus",
  "command": "workbench.action.nextEditor"
},
{
  "key": "ctrl+shift+tab",
  "when": "terminalEditorFocus",
  "command": "workbench.action.previousEditor"
}

Depending on the size of the VSCode window, the position of the panel might vary. Sometimes it needs to be on the right of the editor, and sometimes below. I do most of my window management using Rectangle.app's keyboard shortcuts, so it's most efficient if I can follow one of those combos with another in VSCode. The following bit of config sets up VSCode so that โŒ˜โ‡งโ†’ and โŒ˜โ‡งโ†“ move it to those positions.

This is going to be more lines of config than you're probably expecting. The reason for the bloat here is that this way preserves keyboard focus. If you just run workbench.action.positionPanelRight, then afterwards you have to refocus whatever bit of UI you were working in. The keybindings here detect whether you're invoking the shortcuts from inside a terminal or not, and ensure you land back where you started.

{
  "key": "cmd+shift+right",
  "when": "terminalFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.positionPanelRight",
      "workbench.action.terminal.focus"
    ]
  }
},
{
  "key": "cmd+shift+down",
  "when": "terminalFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.positionPanelBottom",
      "workbench.action.terminal.focus"
    ]
  }
},
{
  "key": "cmd+shift+right",
  "when": "!terminalFocus && !terminalEditorFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.positionPanelRight",
      "workbench.action.focusActiveEditorGroup"
    ]
  }
},
{
  "key": "cmd+shift+down",
  "when": "!terminalFocus && !terminalEditorFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.positionPanelBottom",
      "workbench.action.focusActiveEditorGroup"
    ]
  }
}

VSCode's support for placing terminals in the editor area is brilliant when you're doing something really terminal centric. Sometimes a little panel off to the side isn't big enough. By default, this is a mouse-driven interaction though. If I'm in a terminal in a bottom panel, I want โŒ˜โ‡งโ†‘ to move it into the editor area, hide the panel, and focus the terminal. This next bit of config makes that happen.

{
  "key": "cmd+shift+up",
  "when": "terminalFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.togglePanel",
      "workbench.action.terminal.moveToEditor",
      "workbench.action.focusActiveEditorGroup"
    ]
  }
},

For the reverse scenario, when I want to clear away my editor area terminal back down into the panel, this entry makes โŒ˜โ‡งโ†“ do that.

{
  "key": "cmd+shift+down",
  "when": "terminalEditorFocus",
  "command": "runCommands",
  "args": {
    "commands": [
      "workbench.action.terminal.moveToTerminalPanel",
      "workbench.action.positionPanelBottom"
    ]
  }
},

That's pretty much it. It's just enough so that I can shuffle around the position of the panel and move terminals in and out of it using the keyboard. Apparently that's all I ever actually wanted. It feels pretty fantastic to have the keyboard-driven terminal winxow management I love without sacrificing any of the benefits that come from using the most popular tool in my corner of the industry. Much like using SQLite in production, it feels like it shouldn't even be possible. I'm certainly in a real happy place these days regarding devtools.

Future Tweaks

Yesterday, I decided the final piece of the puzzle would be to have VSCode start up with the terminal open in the editor area. I chucked vscode startupeditor terminal into Google and found my way to a GitHub issue thread titled "workbench.startupEditor should support opening a terminal in editor area". It had a bunch of other people back in 2022 describing exactly what I was looking for.

This is a type of search result I normally associate with disappointment. The purple "Closed" badge here normally means "thanks, but no thanks". Not this time though. I scrolled to the bottom and could hardly believe what I was seeing: a pull request, merged 4 days ago, titled Add terminal as a startup editor. OMFG! So when that commit makes it into a shipped build, the config line to use it will be like this.

"workbench.startupEditor": "terminal",

Can't wait! In the meantime, the entire config all together is available as a gist.