2

I was wondering, is it possible to play asciinema.org screen recordings inside LaTeX Beamer frame?

Here is an example link of a screen recording: https://asciinema.org/a/418574. Note that its original format is .cast.


Three approaches provided by asciinema.org:

  1. HTML:
<a href="https://asciinema.org/a/418574" target="_blank"><img src="https://asciinema.org/a/418574.svg" /></a>
  1. Markdown:
[![asciicast](https://asciinema.org/a/418574.svg)](https://asciinema.org/a/418574)
  1. Embed the player:
<script id="asciicast-418574" src="https://asciinema.org/a/418574.js" async></script>
AlexG
  • 54,894
alper
  • 1,389
  • Look into converting to either video https://github.com/opcode-eu-org-libs/asciicast2movie or to gif (and then convert the gif into individual images and include those in your presenation) – samcarter_is_at_topanswers.xyz Jan 25 '23 at 12:13
  • When the gif is generated there would be no time bar at bottom to play video. Also https://github.com/marionebl/svg-term-cli looks like better approach to start from – alper Jan 25 '23 at 17:02

1 Answers1

4

Update: player options

Playing asciinema.org screen recordings interactively is possible inside beamer class presentations.

However, asciinema.org relies on HTML5 standards which exclude PDF as an output format. So we need to resort to SVG which plays well in modern Web browsers, such as Chrome, Chromium, Edge and Firefox.

The code example below defines

\includeasciinema{<width>}{<height>}{<asciinema id number>}[<player options>]

which takes the widget dimensions and the numeric asciinema id, here: 418574, as mandatory arguments. One needs to play a bit with the size arguments in order to make the widget fit on a beamer slide without showing a vertical scrollbar.

The fourth, optional argument allows for further tweaking the player behaviour. Among the player options listed on the GitHub page, the most useful are:

autoplay=true
loop=true
startAt=<ss> | <mm>:<ss> | <hh>:<mm>:<ss>
speed=<number .gt. 0.0> 

Multiple player options have to be combined with an ampersand ("&"), i. e.

loop=true&speed=0.5&startAt=5

Note that autoplay is misspelled as autoPlay on the GitHub page, which does not work. Also, startAt implies autoplay.

The code for slide navigation (PgUp, PgDn, Home, End, mouse left/right click, mouse wheel, cursor auto-hide) is taken from another post.

SVG output is produced with dvilualatex and dvisvgm (assuming input file example.tex):

dvilualatex example
dvilualatex example
dvisvgm --zoom=-1 --font-format=woff2 --bbox=papersize --page=1- --linkmark=none example

Then, open example-1.svg in a Web browser.

Live example (click to start presentation, navigate via keyboard or mouse l/r click, F11 for full-screen):

Complete code with loop and speed player options set:

\documentclass[dvisvgm,hypertex,aspectratio=169]{beamer}

\usefonttheme{serif}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % asciinema inclusion command %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \includeasciinema{<width>}{<height>}{<asciinema id number>}[<player options>] % % options example: autoplay=true&loop=true&speed=0.5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ExplSyntaxOn \NewDocumentCommand\includeasciinema{mmmO{}}{ \group_begin: \str_set:Nx\l_ascma_optarg_str{#4} \str_replace_all:Nnn\l_ascma_optarg_str{&}{&amp;} \leavevmode \special{dvisvgm:bbox~\dim_eval:n{#1}~\dim_eval:n{#2}~0pt~transform} \tl_set:Nx\l_ascma_viewbox_wd_tl{\fp_eval:n{ \g_ascma_px_per_bp_tl\dim_to_decimal_in_bp:n{#1}}} \tl_set:Nx\l_ascma_viewbox_ht_tl{ \fp_eval:n{\g_ascma_px_per_bp_tl\dim_to_decimal_in_bp:n{#2}}} \special{dvisvgm:raw <g~transform='translate({?x},{?(y-(\dim_to_decimal_in_bp:n{#2}))})'> <svg~ width='\dim_to_decimal_in_bp:n{#1}'~ height='\dim_to_decimal_in_bp:n{#2}'~ viewBox='0~0~\l_ascma_viewbox_wd_tl\space\l_ascma_viewbox_ht_tl' > <foreignObject~width='\l_ascma_viewbox_wd_tl'~height='\l_ascma_viewbox_ht_tl'> <g~xmlns='http://www.w3.org/1999/xhtml'> <iframe~ width='100\ascma_percent:'~height='100\ascma_percent:'~frameborder='0'~ allowfullscreen='true'~title='asciinema~player'~ src='https://asciinema.org/a/#3/iframe?\l_ascma_optarg_str' /> </g> </foreignObject> </svg> </g> } \hbox_to_wd:nn{#1}{\vrule~width~\c_zero_dim~height~\dim_eval:n{#2}~depth~0pt\hss} \group_end: } % assumed vert. screen resolution, for setting <svg> viewBox dimensions \tl_const:Nn\g_ascma_screen_px_tl{1080} % Full HD \tl_const:Nx\g_ascma_px_per_bp_tl{\fp_eval:n{\g_ascma_screen_px_tl/\dim_to_decimal_in_bp:n{\paperheight}}} \group_begin: \char_set_catcode_other:N% \cs_new_nopar:Nn\ascma_percent:{%} \group_end: \ExplSyntaxOff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % slide navigation via keyboard and mouse left-or-right-click/mouse wheel, % mouse cursor autohide on idle; navigation symbols <--, --> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{fontawesome5} \setbeamertemplate{navigation symbols}{} \AddToHook{shipout/before}{\xdef\currentPageNumber{\inteval{\ReadonlyShipoutCounter+1}}} \AddToHook{shipout/foreground}{% \put(0,0){% \raisebox{-\dimexpr\height+0.5ex\relax}[0pt][0pt]{\makebox[\paperwidth][r]{% \normalsize\color{structure!40!}% \ifnum\currentPageNumber>1% \href{\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber-1\relax}.svg}{\faArrowLeft}% \else% \textcolor{lightgray}{\faArrowLeft}% \fi\hspace{0.5ex}% \ifnum\currentPageNumber<\PreviousTotalPages% \href{\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber+1\relax}.svg}{\faArrowRight}% \else% \textcolor{lightgray}{\faArrowRight}% \fi% \hspace{0.5ex}% }}% }% \special{dvisvgm:raw <style>svg{cursor: none}</style>% <defs>% <script type="text/javascript">% <![CDATA[% var cursorTimer;% var downOnLink=false;% var downOnRoot=false;% function islink(tg){return (tg.tagName=='a') ? true : tg.parentNode ? islink(tg.parentNode) : false;};% function ismmedia(tg){return (tg.tagName=='video'||tg.tagName=='audio') ? true : tg.parentNode ? ismmedia(tg.parentNode) : false;};% document.addEventListener('mousemove', function(e){% if(islink(e.target)||ismmedia(e.target)||e.target.getAttribute('class')=='annot'){% e.target.style.cursor='pointer';}else{e.target.style.cursor='default';}% try{clearTimeout(cursorTimer);}catch(err){};% cursorTimer=setTimeout(function(){e.target.style.cursor='none';},3000);% });% window.addEventListener('contextmenu', function(e){% capture right click if(!islink(e.target)&&!ismmedia(e.target)) e.preventDefault();% });% document.addEventListener('mousedown', function(e){% if(islink(e.target)||ismmedia(e.target)) downOnLink=true;% else downOnRoot=true;% });% document.addEventListener('mouseup', function(e){% if(downOnLink||!downOnRoot){downOnLink=false;return;}% downOnRoot=false;% \ifnum\currentPageNumber<\PreviousTotalPages if(!e.shiftKey&&e.button==0) document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber+1\relax}.svg');% \fi% \ifnum\currentPageNumber>1 if(e.shiftKey||e.button>1) document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber-1\relax}.svg');% \fi% });% document.addEventListener('wheel', function(e){% \ifnum\currentPageNumber<\PreviousTotalPages if(e.deltaY>0){% document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber+1\relax}.svg');% }% \fi% \ifnum\currentPageNumber>1 if(e.deltaY<0){% document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber-1\relax}.svg');% }% \fi% });% document.addEventListener('keydown',function(e){% \ifnum\currentPageNumber<\PreviousTotalPages if(e.key=='PageDown'||e.key=='ArrowDown'||e.key=='ArrowRight')% document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber+1\relax}.svg');% \fi% \ifnum\currentPageNumber>1 if(e.key=='PageUp'||e.key=='ArrowUp'||e.key=='ArrowLeft')% document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{\the\numexpr\currentPageNumber-1\relax}.svg');% \fi% if(e.key=='Home') document.location.replace('\jobname-\zeroPad{\PreviousTotalPages}{1}.svg');% if(e.key=='End') document.location.replace('\jobname-\PreviousTotalPages.svg');% });% ]]>% </script>% </defs>% }% }% % helper macro \zeroPad : zero-pads integer according to template, % e. g. 123 --> 00123 if template is 99999 % #1: arbitrary integer number as template specifying the % width, e. g. `987654' for a width of 6 digits % #2: the number to be formatted \def\zeroPad#1#2{\zeroPadI{\zeroTemplate{0}{#1}}{#2}} %low level macros used by \zeroPad \def\zeroPadI#1#2{% #1: string of zeros specifying width, #2 number \ifnum1#2<1#1 \zeroPadI{#1}{0#2}% \else% #2% \fi% }% \def\zeroTemplate#1#2{% create template (string of zeros) from given num \ifnum10#1>1#2 #1% \else% \zeroTemplate{0#1}{#2}% \fi% }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\title{Embedding \emph{asciinema} screen recordings} \subtitle{Use a Web browser and press \framebox{F11}} \author{AlexG} \date{\today}

\begin{document}

\frame{\titlepage}

\begin{frame}{Game of Life example} \includeasciinema{0.4\textwidth}{0.48\textwidth}{418574}[loop=true&speed=0.5] \end{frame}

\end{document}

AlexG
  • 54,894
  • Which web browser do you recommend to use? and what is F11 shortcut to? F11 is detected as volume control key in macOS Safari.. – alper Jan 26 '23 at 14:46
  • In Chrome, Edge, Opera, Firefox, ...., F11 sets the browser to full-screen, good for presentations. I assumed this ubiquitous. Didn't know Safari makes an exception here. – AlexG Jan 26 '23 at 15:02
  • 2
    @alper control+command+F in Safari – samcarter_is_at_topanswers.xyz Jan 26 '23 at 15:02
  • We are not required to upload the presentation into gitlab right? – alper Jan 26 '23 at 20:03
  • No, not at all! As written in the answer, open one of the generated local SVG files in the Web browser and start navigating with the mouse wheel or buttons or with PgUp / PdDn on the keyboard. – AlexG Jan 26 '23 at 20:06
  • On the other hand, I don't know how to deal with local screen recordings. My code currently works with online examples provided by https://asciinema.org/explore. – AlexG Jan 26 '23 at 20:10
  • @AlexG No worries for local screen recordings, I was uploading the recordings into asciinema that I want to put in the presentation any way :-) – alper Jan 30 '23 at 06:56
  • Fine! Besides, I added a 4th, optional argument to the inclusion command. It allows the player behaviour to be further tweaked, e. g. looping playback, speed etc. – AlexG Jan 30 '23 at 07:52