asciinema & asciicast2gif
Sometimes a help text to convey how to properly use a command, or a help text exists but people are not reading it. In these cases a short video might do the trick. asciinema is quite popular and allows to record terminal sessions and replay them later on:
sudo dnf install asciinema
Record sessions with asciinema rec, play sessions with asciinema play, cool.
Update: asciicast2gif is no longer maintained and agg appears to be the successor, and is much faster than asciicast2gif. Once all this was installed, generating GIFs was easy enough. Stitching both tools togeter:
$ asciinema rec demo.cast timeout 5 asciiquarium ^D $ agg demo.cast demo.gif
Et voilà:

For posterity, let's leave these old notes in place:
$ asciicast2gif /tmp/test.cast /tmp/test.gif
[...]
convert -loop 0 -delay 20 /tmp/tmp.UccOho2kuG/0.png \
-delay 420 /tmp/tmp.UccOho2kuG/1.png \
-delay 86 /tmp/tmp.UccOho2kuG/2.png \
[...] -layers Optimize gif:- | gifsicle -k 64 -O2 -Okeep-empty --lossy=80 -o /tmp/test.gif
And looking in dmesg revealed that convert was running out of memory while trying to convert a ~30 second screen cast recording! After granting the machine a bit more memory, the command completed and we now had a working GIF to embed in our web page:
$ asciicast2gif -t tango test.cast test.gif ==> Loading test.cast... ==> Spawning PhantomJS renderer... ==> Generating frame screenshots... ==> Combining 137 screenshots into GIF file... gifsicle: warning: huge GIF, conserving memory (processing may take a while) ==> Done. $ mv test.gif ~/www/ $ cat ~/www/test.md [...] [video](test.gif)
Note: limiting the memory usage
of the node process did not seem to work, as can be seen in top:
Tasks: 117 total, 2 running, 115 sleeping, 0 stopped, 0 zombie
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 2.0 us, 0.0 sy, 0.0 ni, 74.0 id, 24.0 wa, 0.0 hi, 0.0 si, 0.0 st
GiB Mem : 7.8 total, 1.7 free, 6.0 used, 0.1 buff/cache
GiB Swap: 0.1 total, 0.0 free, 0.1 used. 1.6 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1971 dummy 20 0 5996.9m 5.8g 1.5m R 103.0 75.0 1:05.03 convert -loop 0 -delay 13 [...]
1958 dummy 20 0 635.3m 30.7m 0.2m S 0.0 0.4 0:05.03 node --max-old-space-size=512 [...]
The actual gif quality varies depending on what's shown on the terminal. Movie like sequences look a bit
crappy though, but that's not what we wanted to do in the first place, hm? :-)

error message
gifsicle:<stdin>: empty file
at checkExecSyncError (child_process.js:630:11)
at Object.execSync (child_process.js:666:15)
at Dp (/home/dummy/node_modules/asciicast2gif/main.js:708:246)
at /home/dummy/node_modules/asciicast2gif/main.js:713:178
at Function.b [as h] (/home/dummy/node_modules/asciicast2gif/main.js:709:287)
at ep (/home/dummy/node_modules/asciicast2gif/main.js:697:48)
at /home/dummy/node_modules/asciicast2gif/main.js:697:193
at /home/dummy/node_modules/asciicast2gif/main.js:689:264
at Immediate.Po (/home/dummy/node_modules/asciicast2gif/main.js:685:331)
at processImmediate (internal/timers.js:456:21) {
status: 1,
signal: null,
output: [
null,
Buffer(0) [Uint8Array] [],
Buffer(29) [Uint8Array] [
103, 105, 102, 115, 105, 99, 108,
101, 58, 60, 115, 116, 100, 105,
110, 62, 58, 32, 101, 109, 112,
116, 121, 32, 102, 105, 108, 101,
10
]
],
pid: 2836,
stdout: Buffer(0) [Uint8Array] [],
stderr: Buffer(29) [Uint8Array] [
103, 105, 102, 115, 105, 99, 108,
101, 58, 60, 115, 116, 100, 105,
110, 62, 58, 32, 101, 109, 112,
116, 121, 32, 102, 105, 108, 101,
10
]
}