Sometimes we need to create a demo for project showcase, bug report, or tutorial. But how to create idempotent, stunning, and a demo that hides secret information?

Idempotent #

Commands, speed, and layout are prone to change in each iteration. We need to keep them consistent.

To make consistent command and speed, I use doitlive. It lets you write a list of commands that will be fired during the demo. Inside doitlive, you just need to press any key to feeds the command to the app.

I always saved the command list in the documentation directory or the contribution guide. It helps the next maintainer to produce a similar demo faster. It also acts as a safety net for me to recreate the demo in a matter of seconds if I need to change something.

Another interesting feature is the ability to style the terminal prompt. You nor the contributor do not need to change the terminal prompt or even changing the shell to make the demo looks similar or hides the credentials.

Because no real typing invoked here. The speed of invoking each command will be similar to the previous demo. This result in the consistency of style and speed

# project/docs/demo.sh

#doitlive prompt: >
#doitlive shell: /bin/fish
#doitlive speed: 3
zman
zman month
zman week
zman year --width 40
zman year --full-bar ▮ --rest-bar ▯

To keep the dimension in the next demo, I use the script below to get the window size and document it same place as the previous step.

#!/bin/bash

# Get the coordinates of the active window's
# top-left corner, and the window's size.
# This excludes the window decoration.
# https://unix.stackexchange.com/a/14170/141936
unset x y w h
eval $(xwininfo -id $(xdotool getactivewindow) |
sed -n -e "s/^ \+Absolute upper-left X: \+\([0-9]\+\).*/x=\1/p" \
-e "s/^ \+Absolute upper-left Y: \+\([0-9]\+\).*/y=\1/p" \
-e "s/^ \+Width: \+\([0-9]\+\).*/w=\1/p" \
-e "s/^ \+Height: \+\([0-9]\+\).*/h=\1/p" )

echo -n "x: $x y: $y w: $w h: $h"

Safe #

I need to make sure not to leak any sensitive information during the demo. username and machine name in terminal prompt already handled by doitlive. Now let's manage other places.

Emacs always show the full path when writing a file. I don't like this behavior. Instead of saying Wrote /home/username/project/foo.txt, I want it to be Write foo.txt.

;; aza-screncast.el

;; Enable the module before doing screencast
;; it will hide `save-buffer' "Wrote ..." message that contains buffer's path
;; and show buffer's filename instead

;; @https://emacs.stackexchange.com/a/62516/11777
(defun sb/inhibit-message-call-orig-fun (orig-fun &rest args)
"Hide messages appearing in ORIG-FUN, forward ARGS."
(let ((inhibit-message t))
(apply orig-fun args)))

(advice-add 'write-region :around #'sb/inhibit-message-call-orig-fun)
(advice-add 'save-buffer :around #'sb/inhibit-message-call-orig-fun)

(defun hide-save-buffer-message (&optional arg)
"Adds feedback after `save-buffer' without showing the buffers' path."
(message "Wrote %s" (buffer-name)))

(advice-add 'save-buffer :after #'hide-save-buffer-message)

I only enabled the module when doing the demo. If you use a package such marginalia, it is better to disable it too.

Sometimes, the sensitive info also in the window title. I need to hide them.

#!/usr/bin/env bash

# Depends on: xdotool, wmctrl
# credits: majkinetor @ https://faq.i3wm.org/question/4074/changing-window-title.1.html

FOCUSED=$(wmctrl -lp | grep $(xprop -root | grep _NET_ACTIVE_WINDOW | head -1 | awk '{print $5}' | sed 's/,//' | sed 's/^0x/0x0/'))
echo $FOCUSED
FPID=$(echo $FOCUSED | awk '{print $3}')
FNME=$(echo $FOCUSED | cut -f -4 -d ' ' --complement)
xdotool search -all --pid $FPID --name "$FNME" set_window -name "$*"

In case you use tmux, you can change the pane title using Ctrl + b + ,.

Stunning #

Improve the end quality. Cut the excess frame using ezgif. Don't let the demo shows a long paused frame or a cursor pressing the quit button.

The color scheme is a matter of preference, But I love the demo in white color scheme instead of the dark.

Previously, I use Screencast to create a GIF demo. It's lighter and has smaller output compared to others. But now peek resolve many of its problems, and I migrated to Peek since then.