i3wm screencasting gifs

2019-05-24, updated 2019-05-25 — tech blog   ⇦Animating gifs in orgmodeDisqus and javascript random thoughts⇨

I read an amazing comment on reddit about how to very easily record the screen into gifs and I'll report it here with some improvements. All of this can be used in any other window manager, as long as you can create keyboard shortcuts.

1 Create shortcut to start and stop screenrecording

First we create a shortcut to start and stop the screenrecording

bindsym Shift+Ctrl+Print exec ~/.files/i3/record-screen.sh gif
bindsym Shift+Mod4+Print exec ~/.files/i3/record-screen.sh ogv

2 record-screen.sh

This is the file where most things happen.

Dependencies: byzanz-record , slop.

It uses byzanz to record the screen, and slop to select which screen to record from, as well as the --exec flag. --exec makes it so byzanz records until that process exists. This allows us to control exactly for how long the recording will last since we can simply kill it using our shortcut.

#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
IS_RECORDING_PID=`pgrep -a -f is-recording | cut -f1 -d' '`
IS_RECORDING_SH=$HOME/.files/i3/is-recording.sh

if [[ "$IS_RECORDING_PID" == "" ]]; then
      read -r X Y W H < <(slop -n -l -c 0.157,0.333,0.466,0.4 -f "%x %y %w %h")
      FILE_NAME=~/Videos/Screencast-$(date -Iseconds | cut -d'+' -f1).$1
      case "$1" in
              byzanz)
                      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME >& /dev/null
                      ;;
              gif)
                      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME >& /dev/null
                      ;;
              ogv)
                      byzanz-record -a -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME >& /dev/null

                      if [[ "$2" == "--convert-to-gif" ]]; then
                              sleep 1
                              $DIR/convert-ogv-to-gif.sh $FILE_NAME | xclip -selection clipboard
                      fi
                      ;;
      esac
else
      polybar-msg hook is-recording 1
      kill $IS_RECORDING_PID
fi

3 is-recording.sh

This is the process that when killed stops the recording.

#!/usr/bin/env bash

polybar-msg hook is-recording 2

while true; do
      sleep 60
done

4 Improvements and changes

4.1 Making the gif smaller

Recording a gif using the above files will result in files that are unreasonably large. A 10s recording might take 10mb!

Therefore the first thing we should do is optimize the gif so that it is smaller. Luckily there is a program that does just that: gifsicle. Since there are very few changes between each frame in a screencast, this can turn 10mb files into 100kb files!

This is the relevant change:

gif)
      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME
      gifsicle --batch --optimize=3 $FILE_NAME
      ;;

4.2 Copying the file to the clipboard

After you've save the file, it is useful to have it copied to the clipboard, so you can you use it in another place. In my case, I like being able to paste the screencast directly to my orgmode files by using my clipboard2org package, but you can use other programs.

This depends on xclip.

echo $FILE_NAME| xclip -i -selection clipboard -t text/uri-list

4.3 Displaying a notification when you finish recording

I do not use polybar. So instead I use notify-send.sh to send a notification when we finish the recording so I know that the command worked:

~/.config/i3/notify-send.sh/notify-send.sh -i display  "finished recording"
fi

4.4 Recording webms

Webms are better than gifs when supported. They are supported by basically everything, except IOS devices and internet explorer. In other words, it is even better than being supported everywhere haha.

webm)
      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME
      ;;

4.5 Putting it all together

This is the end result. The Dependencies: byzanz-record , slop, gifsicle, notify-send.sh.

All of the paths are based on the paths I've setup here, you should adapt them to your case.

#!/usr/bin/env bash
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
IS_RECORDING_PID=`pgrep -a -f is-recording | cut -f1 -d' '`
IS_RECORDING_SH=$HOME/.tools/is-recording.sh

if [[ "$IS_RECORDING_PID" == "" ]]; then
      read -r X Y W H < <(slop -n -l -c 0.157,0.333,0.466,0.4 -f "%x %y %w %h")
      FILE_NAME=~/Videos/Screencast-$(date -Iseconds | cut -d'+' -f1).$1
      case "$1" in
              byzanz)
                      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME 
                      ;;
              gif)
                      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME
                      gifsicle --batch --optimize=3 $FILE_NAME
                      ;;
              webm)
                      byzanz-record -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME
                      ;;
              ogv)
                      byzanz-record -a -w $W -h $H -x $X -y $Y -c --exec="$IS_RECORDING_SH" $FILE_NAME 

                      if [[ "$2" == "--convert-to-gif" ]]; then
                              sleep 1
                              $DIR/convert-ogv-to-gif.sh $FILE_NAME | xclip -selection clipboard
                      fi
                      ;;
      esac
      echo $FILE_NAME| xclip -i -selection clipboard -t text/uri-list
else
      #polybar-msg hook is-recording 1
      kill $IS_RECORDING_PID
      ~/.config/i3/notify-send.sh/notify-send.sh -i display  "finished recording"
fi

5 Example!

Screencast-2019-05-24T044159-0400.gif

Author: Ivan Tadeu Ferreira Antunes Filho

Date: 2022-07-23 Sat 05:11

Github: github.com/itf

Made with Emacs 27.1 (Org mode 9.3) and Org export head