%\iffalse meta-comment
%
% Copyright (C) Walter Daems <walter.daems@uantwerpen.be>
%
% This work may be distributed and/or modified under the conditions of
% the LaTeX Project Public License, either version 1.3 of this license
% or (at your option) any later version.  The latest version of this
% license is in:
% 
%    http://www.latex-project.org/lppl.txt
% 
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Walter Daems.
%
% \fi
%
% \iffalse
%
%<@@=beamerreveal>
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{beamer-reveal.dtx}
             [2026-02-04 v1.08 beamer-reveal]
%</driver>
%<*reveal>
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{beamer-reveal}
                [2026-02-04 v1.08 beamer-reveal]
\RequirePackage{expl3}
\RequirePackage{xparse}
\RequirePackage{tikz}
\usetikzlibrary{calc}
\RequirePackage{currfile}
%</reveal>
%<*driver>
\documentclass[a4paper,10pt]{ltxdoc}
\usepackage{geometry}
% In the preamble
\renewenvironment{macro}[1]{%
  \par\addvspace{1.0\baselineskip}%
  \begingroup
  % Typeset the name as a paragraph heading
  \hspace*{-0.75cm}
  \begin{minipage}{\textwidth}
    \rule{3cm}{1pt}\\
    \hspace*{1ex}\texttt{\string#1}\\
    \rule[0.25\baselineskip]{3cm}{1pt}
  \end{minipage}
  % Index it:
  \SpecialMainIndex{#1}%
  \endgroup
  \ignorespaces
}{%
  \par\addvspace{0.5\baselineskip}%
}
\usepackage{newpxtext,newpxmath}
\linespread{1.05}
\def\fileversion{v1.08}
\def\filedate{2026-02-04}
\usepackage{makeidx}
\usepackage{amsmath}
\usepackage{alltt}
\usepackage{booktabs}
\usepackage{metalogo}
\usepackage{enumitem}
\usepackage{rotating}
\usepackage{tikz}
\usetikzlibrary{arrows}
\tikzset{>=stealth'}
\IfFileExists{tocbibind.sty}{\usepackage{tocbibind}}{}
\IfFileExists{hyperref.sty}{
  \usepackage[bookmarksopen]{hyperref}
  \hypersetup{citecolor=blue,linkcolor=blue}
  \hypersetup{hypertexnames=false}
}{}

\EnableCrossrefs
\CodelineIndex
\RecordChanges
\newlist{arguments}{description}{2}
\setlist[arguments]{leftmargin=3em,topsep=0pt,itemsep=0.5ex,parsep=0pt}
\newlist{options}{description}{2}
\setlist[options]{leftmargin=10em,style=nextline,topsep=0pt,itemsep=0.5ex,parsep=0pt}
\newcommand\beamerreveal{\textsc{beamer-reveal}}
\newcommand\beamer{\textsc{beamer}}
\newcommand\Beamer{\textsc{Beamer}}
\setlist[itemize]{itemsep=0.5ex,topsep=0pt,parsep=0pt}
\setlist[enumerate]{itemsep=0.5ex,topsep=0pt,parsep=0pt}
\begin{document}
  \DocInput{beamer-reveal.dtx}
\end{document}
%</driver>
% \fi
%
% \changes{v0.80}{2025/12/21}{\@ alpha 1 embryonic demo version}
% \changes{v0.85}{2025/12/21}{\@ alpha 2 tested by Walter, functional
% on Linux}
% \changes{v0.90}{2025/12/24}{\@ beta 1 tested by Paul, not
% functional on MS-Windows}
% \changes{v0.95}{2025/12/17}{\@ beta 2 tested by Paul, functional on MS-Windows}
% \changes{v1.00}{2025/12/30}{\@ first appearance on CTAN}
% \changes{v1.01}{2026/01/02}{\@ restored pdflatex compatibility (including macro-based accented characters)}
% \changes{v1.02}{2026/01/02}{\@ no changes - needed to correct faulty upload}
% \changes{v1.03}{2026/01/19}{\@ introduced new command-line options to accomodate users of latexmk}
% \changes{v1.04}{2026/01/22}{Assigned node to rectangle boundingbox of video/animation/image/audio such that positioning relative to the bounding box (via its anchors) is possible}
% \changes{v1.05}{2026/01/23}{\@ new feature release}
% \changes{v1.05}{2026/01/23}{\@- implemented both overlay-mode and insert-mode media types}
% \changes{v1.05}{2026/01/23}{\@- breaking syntax change: 'at' must be replaced by '\textbackslash at')}
% \changes{v1.05}{2026/01/23}{\@- removed x-y distortion from animations}
% \changes{v1.06}{2026/01/25}{\@ new feature release}
% \changes{v1.06}{2026/01/25}{\@- regular bugfixes}
% \changes{v1.06}{2026/01/25}{\@- renamed extractloleft and extractupright to avoid nameclashes}
% \changes{v1.06}{2026/01/25}{\@- reverted to short versions of frametitle for menu entries}
% \changes{v1.06}{2026/01/25}{\@- improved animation generation space trimming and error logging}
% \changes{v1.06}{2026/01/27}{\@- implemented embedding of media files}
% \changes{v1.07}{2026/01/30}{\@ new feature release}
% \changes{v1.07}{2026/01/29}{\@- allow for multiple handout slides per animation}
% \changes{v1.07}{2026/01/29}{\@- enabled (full graphical) speaker notes}
% \changes{v1.08}{2026/02/04}{\@ new feature release}
% \changes{v1.08}{2026/02/01}{\@- implemented stills as a complementing feature to animations}
% \changes{v1.08}{2026/02/01}{\@- added pause key 'v' for video player
% and 'a' for audio player, 'i' to initialize/reset all videos/audios}
% \changes{v1.08}{2026/02/04}{\@- implemented autoslide mode, together
% with loop mode, that allows for kiosk presentations}
% \changes{v1.08}{2026/02/04}{\@- fixed notes being not only notes
% bug}
% \changes{v1.08}{2026/02/04}{\@- extended embedding mode to also work
% for slide backgrounds and notes (not yet for animations and stills)}
% 
% \DoNotIndex{\group,\_,\AddToHook,\bool,\box,\c,\cs,\dim,\ExplSyntaxOn,\ExplSyntaxOff,\ProcessKeyOptions,\beamer@frametitle,\insertpagenumber,\insertframenumber,\insertoverlaynumber,\inserttitle,\int,\iow,\keys,\message,\msg,\newdimen,\only,\pageheight,\pagewidth,\path,\pgfmathsetmacro,\secname,\subsecname,\textcolor,\sys,\RequirePackage,\fp,\tl,\AtEndDocument,\newcommand,\newenvironment,\begin,\bfseries,\draw,\clip,\else,\fi,\if,\fill,\filldraw,\ifthenelse,\ifx,\textwidth,\node,\\,\@empty,\@tempdima,\@tempdimb,\@tempswatrue,\{,\},\ ,\bf,\BODY,\break,\Alph,\and,\define@key,\color,\dx,\dy,\g,\gdef,\hbox,\tiny,\scriptsize,\footnotesize,\small,\normalsize,\large,\Large,\LARGE,\huge,\Huge,\l,\LaTeX,\let,\p@,\relax,\renewcommand,\Requirepackage,\textbf,\textsf,\texttt,\textbackslash,\vspace,\hspace,\hfill,\hskip,\vskip,\hline,\vrule,\typeout,\usebox,\end,\paperheight,\paperwidth,\par,\NewDocumentCommand,\seq,\unexpanded,\p,\y,\x,\@ifundefined,\expandafter,\IfBooleanTF,\IfNoValueTF,\posx,\posy,\jobname,\pgfgetlastxy,\pgfextra,\pdfpageheight,\pdfpagewidth}
% \setlength{\parindent}{0em}
% \addtolength{\parskip}{0.5\baselineskip}
%
% \title{\beamerreveal}
% \author{Walter Daems (|walter.daems@uantwerpen.be|)}
% \date{Release \filedate{} --- \fileversion{}}
% \newgeometry{left=3cm,right=2cm,top=2cm,bottom=2.5cm}
% \maketitle
%
% \section{Introduction}
%
% \Beamer{} \cite{beamer} is a very powerful and convenient document class to create
% presentations and slides.
% However, integrating multimedia in it, is still a bit of a faff.
% On one side you have the integrated |multimedia| facility of \beamer{} \cite{beamer}
% and on the other side the |movie15| \cite{movie15} and |media9|
% \cite{media9} packages. But unless you use the stock acrobat reader on
% Microsoft Windows, these things barely work, if at all.
%
% Next to this \LaTeX{} ecosystem for slides, you have the |reveal.js| framework \cite{reveal}, that allows easy
% integration of multimedia content. Why not combine both worlds? With that I mean:
% \begin{itemize}
%   \item make your slides in \beamer{}, using all the nice packages that
%        come with \LaTeX{},
%   \item include any browser-compatible multimedia content you'd like,
%        even generate some \LaTeX{} animations,
%   \item convert that presentation to the reveal.js framework.
% \end{itemize}
% That's exactly what this package does.
%
% Note that you are an \emph{early adopter} when using this package. Expect frequent changes.
%
% \section{Rationale}
% 
% Let's talk about the elephant in the room: why not work in the |reveal.js|
% framework directly, e.g. using Quarto \cite{quarto}? I see two reasons: 
% \begin{itemize}
%   \item It avoids a new learning curve, allowing you to continue to
%   build on your \LaTeX{} and \beamer{} expertise.
%   \item It avoids that you have to convert your thousands of slides
%   into a new format.
% \end{itemize}
% For me, those are all the reasons I need.
%
% \section{Synopsis}
% 
% Figure~\ref{fig:flow} shows the overall flow. You start by making
% slides (frames) the usual way using the |beamer| class. Your
% source file (|slides.tex|) uses the package |beamer-reveal.sty| and references the
% multimedia files of your choice. These multimedia files
% (e.g. videos) can be super-imposed on any slide you like.
% Your favorite \LaTeX-compiler typesets your slides to PDF and
% produces an auxiliary |.rvl|-file containing extra information for
% the conversion script. 
% The conversion script |beamer-reveal.pl| fuses the PDF and the
% auxiliary file into a reveal.js presentation, using the templates
% provided by the \beamerreveal{} package. In fact, this is done
% by converting your slides to |JPG| format and using them as the
% background on the \textsc{reveal}-slides. The multimedia content
% appears as HTML5 elements on that background.\\
% Notes are also converted to |JPG| format and available in the speaker
% view that is based on notes plugin of |reveal.js|.\\
% You then can use your favorite browser as your viewer instead of the
% good old PDF reader.
% \begin{figure}
%   \centering
%   \begin{tikzpicture}
%     [scale=0.7,transform shape,
%     doc/.style={rectangle,fill=black!10,align=center,minimum
%       width=2cm,minimum height=2cm},
%     tool/.style={rectangle,draw,align=center}]
%     \draw (8.5,3.5) rectangle (12.5,5);
%     \draw[dotted,->] (9,4.5) -- (10,4.5) node[right] {``references''};
%     \draw[->] (9,4) -- (10,4) node[right] {data flow};
%     \node [doc] (slides) at (-3,0) {|slides.tex|\\\footnotesize(source file)};
%     \node [tool] (latex) at (0,0) {\LaTeX{}\\\footnotesize(compiler)};
%     \node [doc] (class) at (0,3) {|beamer.cls|\\\footnotesize(class)};
%     \node [doc] (package) at (0,-4) {|beamer-|\\|reveal.sty|\\\footnotesize(package)};
%     \node [doc] (pdf) at (4,1.25) {|slides.pdf|\\\footnotesize(PDF-file)};
%     \node [doc] (rvl) at (4,-1.25) {|slides.rvl|\\\footnotesize(reveal-file)};
%     \node [tool] (script) at (8,0) {|beamer-reveal.pl|\\\footnotesize(script)};
%     \node [doc] (reveal) at (12,0) {|slides.html|\\\footnotesize(reveal.js website)};
%     \node [doc] (template) at (8,-4) {beamer-reveal-\\templates};
%     \node [doc] (mm) at (6,4) {Multimedia\\files};
%     \draw[->] (slides) -- (latex);
%     \draw[->,dotted] (slides) -- (class);
%     \draw[->,dotted] (slides) -- (package);
%     \draw[->,dotted] (slides) -- (mm);
%     \draw[->,dotted] (reveal) -- (mm);
%     \draw[->,dotted] (pdf) -- (mm);
%     \draw[->,dotted] (rvl.north east) -- (mm);
%     \draw[->] (class) -- (latex);
%     \draw[->] (package) -- (latex);
%     \draw[->] (latex) edge[out=0,in=180] (pdf);
%     \draw[->] (latex) edge[out=0,in=180] (rvl);
%     \draw[->] (pdf) edge[out=0,in=180] (script);
%     \draw[->] (rvl) edge[out=0,in=180] (script);
%     \draw[->] (template) -- (script);
%     \draw[->] (script) -- (reveal);
%     \draw[thick,dashdotted] (-2,-5.5) coordinate(bl) -- (10,-5.5) -- (10,1) -- (6,1) --
%     (6,-2.5) -- (-2,-2.5) -- cycle;
%     \node[anchor=north west] at (bl) {The \beamerreveal{} package};
%   \end{tikzpicture}
%   \caption{Workflow imposed by the \beamerreveal{} package}
%   \label{fig:flow}
% \end{figure}
%
% As a nice bonus, the \beamerreveal{} package allows you to generate
% \LaTeX{} animations. It's not on the level of Manim \cite{manim}, but for shorter animations
% inlined in your deck of slides it is more than functional!
%
% Finally, you can also include material in iframes. Iframes are HTML
% constructs that act as a mini-browser, allowing to incorporate multiple multimedia
% blocks in HTML.
% As an example, this allows incorporating asymptote material that has
% been generated for displaying as HTML using webGL.
% Note that in many cases, your browser will prohibit these iframes to load external
% web content. To solve this, you can run a local webserver and access your presentation
% through it, or you can embed the iframe in the main HTML file.
% This is explained in Section~\ref{sec:usingscript}.
%
% \section{Quirks}
% Combining \beamer{} and \textsc{reveal} posed one major challenge:
% how to make sure that the HTML5 elements appear exactly where you want
% them to be, i.e. perfectly aligned with your \LaTeX{} content as it
% has been converted to PDF. The core of the problem is twofold:
% \begin{itemize}
% \item In \beamer{} the aspectratio of the slides is
% determined by the class option |aspectratio|. Your PDF viewer uses
% letterboxing (black bars on the side) if the aspectratio of your
% presentation does not correspond to the aspectratio of your screen.
% To the other hand, \textsc{reveal} puts your slides fullscreen
% without letterboxing, and therefore the aspectratio is determined by
% the screen resolution.
%
% \item Given the vector-nature of \LaTeX{} and PDF, resolution is not
% a parameter you normally care about (everything is vector graphics anyway),
% while given the pixel-based nature of traditional multimedia files,
% resolution is an issue that you need to think about carefully.
% \end{itemize}
%
% There is only one good solution: ask the users to (1) set the correct
% aspectratio using the beamer class options and (2) 
% specify the width or height of their displaying screen using a
% \textsc{beamer-reveal} class option.
%
% The latter ensures that (a) the background content and the multimedia
% files that are generated based on the \LaTeX{} source, are generated
% with sufficient resolution, and that (b) the file sizes stay within acceptable limits.
%
% Actually, there is a one more problem, and that is that the canvas
% size and aspectratio of the display area in your browser is
% dependent on whether you are viewing full screen or not.
% Therefore, an extra requirement arises: (3) when presenting a slide-deck
% only you must use your browser in full-screen mode. Otherwise, the alignment is off.
%
% In order not to have to care about resolutions or the actual
% |\pagewidth| or |\pageheight| of your presentation, I've chosen to
% impose another constraint: (4) if you want to add multimedia material in overlay mode,
% the user must specify locations on
% the screen (where to put the multimedia content) as relative
% fractions $(x,y)$ where $(0,0)$ corresponds to the bottom left of
% the screen and $(1,1)$ corresponds to the top right of the screen.
%
% \begin{center}
% \begin{tikzpicture}[scale=0.3,font=\footnotesize]
%   \draw[thick] (0,0) rectangle (16,9);
%   \draw[->] (2,2) node[above right] {coordinate $(0,0)$} -- (0,0);
%   \draw[->] (14,7) node[below left] {coordinate $(1,1)$} -- (16,9);
%   \draw[ultra thin] (16.1,9) -- (17,9);
%   \draw[ultra thin] (16.1,0) -- (17,0);
%   \draw[<->] (16.8,9) -- node[right] {|\textbackslash{}pageheight|} (16.8,0);
%   \draw[ultra thin] (0,-0.1) -- (0,-1);
%   \draw[ultra thin] (16,-0.1) -- (16,-1);
%   \draw[<->] (0,-0.8) -- node[below] {|\textbackslash{}pagewidth|} (16,-0.8);
% \end{tikzpicture}
% \end{center}
%
% However, if you have to specify width and heights of the multimedia
% boxes that you want to overlay on your slides, you don't want to
% specify width and height as relative numbers (of the slide width and
% height). In that scenario, displaying a 16:9 video on a 16:10 slide
% with a width equal to a quarter of the slide width, would require
% you to specify: |width=0.25,height=0.225|, which is weird. In
% addition, if you'd have to present at a venue where the
% projector has a different aspectratio from the one you anticipated,
% you would be forced to recalculate all the widths and heights of every
% video or image. You
% don't want that. Presenting on itself already brings sufficient stress without that
% extra worry.\\
% Therefore, I imposed a fifth constraint: (5) the user must always specify either width or
% height of the box (as a fraction of the respective slide width or
% height) together with the aspectratio. Given width and aspectratio
% the \textsc{beamer-reveal} package can correctly determine its
% relative height; likewise height and aspectratio can be converted
% to the correct relative width. Therefore, it is illegal to specify
% both width and height at the same time. As the package knows the aspectratio
% of the screen (set correctly by the user) no recalculations need to
% be done. In the example above, that would mean specifying:
% |width=0.25,aspectratio=16/9|, which is very logical.
%
% When confronted with the situation where you need to present on an old
% |4:3| projector, instead of the |16:10| you are used to, this allows you
% to just change the beamer aspectratio to |43|, recompile, rerun
% |beamer-reveal.pl| and you are good to go on stage.
%
% So summarized, these are the five rules to go by:
% \begin{enumerate}
% \item Set the correct aspectratio as a beamer class option.
% \item Specify the X or Y-resolution of your displaying screen as a
% package option to the \textsc{beamer-reveal} package.
% \item Always put your browser in full-screen-mode when presenting.
% \item Specify positions relative to the slide width and height,
% $(0,0)$ being bottom left and $(1,1)$ being top right.
% \item Specify box sizes of the HTML5 content always as the width or
% length in combination with the aspectratio.
% \end{enumerate}
%
% One final remark: you can put multimedia boxes on your slides in two modes:
% \begin{description}[leftmargin=7em,style=nextline,topsep=0pt,itemsep=0.5ex,parsep=0pt]
% \item[overlay mode] in this mode the box is put on your slide like tikz puts an image
% in overlay mode on a document: it does not consume any space on the slide;
% \item[insert mode] in this mode the box is actually typeset by \LaTeX{} on your slide.
% The actual content (video, image, \ldots) will not be there, but the space will be consumed.
% \end{description}
% Note that for both modes --- to work properly --- your compiler must
% be run twice before running |beamer-reveal.pl|.
%
% \section{Portability}
% These class files should be ready to use with all common modern \LaTeX{}
% compilers that produce PDF (pdf\LaTeX{}, \XeLaTeX{}, \LuaLaTeX{}, \ldots)
% from the major \TeX{}-distributions (TeTeX, TexLive, MikTeX).
% If you experience problems with one of these, please inform the author.
%
% The script |beamer-reveal.pl| is a Perl script, that works on all
% major platforms (UNIX, Linux, BSD, Debian, MS-Windows, MAC-OS,
% \ldots).
% It makes use of the Poppler library and its |pdftoppm| tool, which
% is also available for those platforms.
% In case you want to use \LaTeX{} animations, it also uses your very own
% favorite \LaTeX{}-compiler, |pdfcrop|
% (which is part of the major TeX-distributions) and |ffmpeg| a
% well-known video conversion tool.
%
% If these tools are available on your platform, then all should be well.
%
% \section{Installing the \texttt{beamer-reveal.pl} script}
% \subsection{On Linux-like operating systems}
% Open a terminal with a shell. Below '|$|' represents your shell prompt.
% If needed, update your package list first. Then install the required tools:
% \begin{itemize}
% \item on a Debian-like OS:\\
% |$ sudo apt install -y perl cpanminus poppler-utils \|\\
% |  texlive-extra-utils ffmpeg|
% \item on a Redhat-like OS:\\
% |$ sudo dnf install -y epel-release|\\
% |$ sudo dnf install -y \|\\
% |  https://download1.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm|\\
% |$ sudo dnf install -y perl perl-App-cpanminus poppler-utils \|\\
% |  texlive-pdfcrop ffmpeg|
% \item on openSUSE:\\
% |$ sudo zypper install -y perl perl-App-cpanminus \|\\
% |  poppler-tools texlive-pdfcrop ffmpeg|
% \item on an Arch-like OS:\\
% |$ sudo pacman -Syu --needed perl cpanminus poppler \|\\
% |  texlive-binextra ffmpeg|
% \item on Alpine:\\
% |$ sudo apk add perl cpan-app-cpanminus poppler-utils \|\\
% |  texlive-extra-utils ffmpeg|
% \item on macOS:\\
% |$ brew install perl cpanminus poppler texlive ffmpeg|
% \end{itemize}
%
% \subsection{On MS windows operating systems}
% Open a powershell. Below '|$|' represents the powershell prompt.
% Install the required tools as follows:
%
% \begin{minipage}{\textwidth}
% |$ winget install StrawberryPerl.StrawberryPerl|\\
% |$ winget install -e --id oschwartz10612.Poppler|\\
% |$ winget install MiKTeX.MiKTeX|\\
% |$ winget install Gyan.FFmpeg|\\
% |$ winget install --id Python.Python.3 --source winget|
% \end{minipage}
%
% You probably need to answer 'Yes' quite some times. If you're asked to restart,
% you only need that before moving over to section~\ref{sec:checking} 'Checking your setup'.
% You probably already have MiKTeX installed. In that case you can skip
% that. However, make sure the 'pdfcrop' program (part of MiKTeX) is installed and available
% on your path.
%
% \subsection{Install \beamerreveal{}}
% Open a shell on Linux/macOS, or a powershell prompt on MS-Windows.
% Run the following command at the prompt:
%
% |$ cpanm BeamerReveal|
%
% This will take a while as this needs to install a number of extra Perl
% libraries that have been used in \beamerreveal. You can use the same command to update
% the script if a new release has been made.
%
% The current release number of the Perl package is: |20260204.1417|
%
% You will see that number appear during the installation.
% Any version more recent version number than this one will work. New
% releases will fix bugs that are reported. 
% If there is a breaking change in the Perl package, a new CTAN update will be released as well.
%
% \subsection{Checking your setup}
% \label{sec:checking}
% Open a shell on Linux/macOS, or a command line or powershell prompt on MS-Windows.
% Then see whether you can invoke the help information for the tools.
%
% \begin{minipage}{\textwidth}
% |$ cpanm -h|\\
% |$ pdftoppm -h|\\
% |$ pdfcrop --help|\\
% |$ ffmpeg -h|\\
% \end{minipage}
%
% To test \beamerreveal{} on MS-Windows, run:\\
% |$ beamer-reveal -h|
%
% On any other platform, run:\\
% |$ beamer-reveal.pl -h|
%
% If they all display correct help info, you're good to go.
%
% \section{Using the \texttt{beamer-reveal.pl} script}
% \label{sec:usingscript}
% If you prepared your \beamer{}-presentation according to Section~\ref{sec:usage},
% then converting it into a reveal.js HTML presentation, is as simple as
% running the following command. Make sure the current directory of
% the shell is the directory your \LaTeX{}-source file and your
% compiled PDF-file is in.
% For all commands below, stay in that same working directory!
%
% \begin{minipage}{\textwidth}
% If you document is called |jobname.tex|, then just run:\\
% |$ lualatex jobname.tex|\\
% |$ lualatex jobname.tex|
% \end{minipage}
%
% On MS-Windows, run:\\
% |$ beamer-reveal jobname|
%
% On any other platform, run:\\
% |$ beamer-reveal.pl jobname|
%
% Conversion is very fast. Of course, if you need to render some \LaTeX{}
% animations, it may take a little more than a jiffy. Especially if
% you are working on MS-Windows, because there the generation is fully
% single-threaded.
%
% Some side notes:
% \begin{itemize}
% \item you need to run |beamer-reveal.pl| from the same working directory as your
% \LaTeX{}-compiler; the script needs to be able to access your source files from
% the same viewpoint as your compiler.
% \item |beamer-reveal.pl| also has some convenient command-line options
% to set the |aux| directory (that contains your |.rvl| file), the |pdf| directory
% that is the output directory of your \LaTeX{}-run and the |output| directory
% (in which it will place the resulting reveal site). This allows easy integration
% with some build frameworks such as |latexmk|. Checkout the help message to learn
% about it.\\
% |$ beamer-reveal.pl -h|
% \end{itemize}
%
% Next, you can load your document in your browser, e.g.:
%
% |$ firefox jobname.html|
%
% If your presentation contains iframe content, you need to start a
% local webserver. You don't need a network connection for that. This
% is how:
%
% |$ python -m http.server|
%
% Then, you can access it through: \url{http://localhost:8000}.
%
% As of v1.06 there is an alternative, and that is to make the iframe element
% 'embedded'. This will cause the iframe content to live as Base64-encoded ASCII
% string in the main |\jobname.html| file. Therefore it will be trusted by your
% browser and will load without any complaint.
%
% \section{Demo}
% If you want to see and try out the result of the example that is
% part of this documentation, check:
% \begin{itemize}
% \item a 16-by-9 version on: \url{https://www.digmanwaves.net/beamer-reveal/169}
% \item a 16-by-10 version on:
% \url{https://www.digmanwaves.net/beamer-reveal/1610}
% \end{itemize}
%
% \section{Open issues}
% Below, you'll find a list of open issues. I appreciate any input I
% can get on these matters.
% \begin{itemize}
% \item Regarding browsers, I'm a big fan of Firefox. However, I must admit
% that the Chrome/chromium line does a better job regarding smooth slide
% transitions. I can't seem to get preloading to work in Firefox
% browser, while in Chrome/chromium, it just works out of the box.
% \item I did not yet see any solutions to perform robust letterboxing on a
% browser (i.e. putting black stripes on the top and bottom if you are
% displaying a 16:9 presentation on a 16:10 screen). With robust, I
% mean a solution in which you don't have to change the content of
% your presentation html-file.
% \end{itemize}
%
% \section{Reach out}
% Is there any feature you are missing? Some problems you encounter?
% Some inconsistencies in the interface or the documentation? Some
% additional features that Reveal supports, but are not in
% \beamerreveal? Let me know by dropping me an e-mail.
%
% If you think \beamerreveal{} makes no sense, let me know why you think
% so. I'm keen to learn.
%
% On the other hand, if you like \beamerreveal{} and are using it, just
% send me a kind word. It keeps me going way better than wine or pizza.
%
% \section{Thanks}
%
% Thanks to Paul Levrie for proofreading this documentation and testing the package.
%
%
% \newpage
% \newgeometry{left=4cm,right=2cm,top=2cm,bottom=2.5cm}%
% \section{Usage}
% \label{sec:usage}
%
% \subsection{Package options}
% \subsubsection{Regarding dimensions}
% The following package options are available:
% \begin{options}
% \item[|width|] the width (in pixels) of the screen you will display
% the presentation on
% \item[|height|] the height (in pixels) of the screen you will
% display the presentation on
% \end{options}
% Only specify one of the two options. The other dimension will be
% deduced from the |aspectratio| option that passed onto the beamer
% class.\\
% Higher values will give higher resolution of the slides (in the
% background), but also larger file sizes. A safety factor is already
% used when converting the slides to jpg-format, so taking the true
% height or width is recommended. Only when you are bothered with
% jpg-artifacts in the final result, you should consider increasing
% the width- or height-value.
%
% \subsubsection{Reveal specific stuff}
% The following options are opening up some cool stuff that reveal enables:
% \begin{options}
% \item[|embed|] this causes all graphical material in your slides
% (|.jpg|, |.png|, |.mp4|, |.ogg|, |.wav|, \ldots) including the slide
% backgrounds and the notes slides to be embedded as Base64-encoded
% ASCII string into the HTML. Note however that this still is not the
% case for animations, stills and the |reveal.js| boilerplate
% javascripts.
% \item[|autoslide=<int>|] This causes your presentation to
% progress automatically, going from slides to slide every
% |<int>| milliseconds. You can override this value on an
% individual basis per slide, by providing the same option to the
% beamer |frame| environment.
% \item[|loop|] This causes your presentation to loop; this makes
% sense if you \emph{autoslide} it, enabling to run your presentation
% in \emph{kiosk} mode.
% \end{options}
%
% \subsection{An enhanced frame environment}
%
% \DescribeEnv{frame}
% The frame environment is defined by \beamer{}. However, it is
% equipped with four new environment options by the \beamerreveal{} package:
% \begin{options}
% \item[|titleslide|] specifies that this slide is a title slide. It
% will be on the top level of the reveal menu. This menu can be
% invoked by pressing 'm' in your presentation (or clicking on the
% pan-cake icon on the bottom left of your presentation).
% \item[|sectionslide|] specifies that this slide is a section slide.
% It will be on the second level of the reveal menu.
% \item[|subsectionslide|] specifies that this slide is a subsection
% slide. It will be on the third level of the reveal menu.
% \item[|transition|] one of |none| (default), |fade|, |zoom|, |concave| or
% |convex|; these correspond to the available reveal.js transitions.
% Not recommended for use. Why? Animation without purpose is bad
% practice. 
% \item[|embed|] This will cause the slide background, the notes and
% all media elements on your slide to be embedded as a Base64-encode
% ASCII string in your HTML file.
% \item[|autoslide=<int>|] This will set the individual time for
% this slide to |<int>| milliseconds. This option only takes effect
% if you set the package option |autoslide| as well. If you set the
% value to 0, the presentation wil stop the autoslide mode at that
% slide. If your slide contains a video or audio fragment, or an
% animation that plays for a specific aumount of time, then this time
% will override the value you specify here. The slide show will only
% progress as soon as the animation or video/audio has finished!
% \end{options}
%
% Slides that are not titleslides, sectionslides or subsectionslides
% are ordinary slides. They will appear on the lowest level in the
% reveal menu. 
%
% \subsection{The macros to use inside the frame environment} 
% To understand the operation of the macros, it is important to
% realize that the slide content of your beamer-generated PDF will be
% put as a background image onto the reveal.js slides.
% The extra material such as videos, images and audio will be put as
% an overlay on top of that background. The macros allow you to define
% what material to put in overlay and where and how big it
% should appear.
% All macros take options. Some of the options need a value, some not.
% Options that take no value are marked with a dagger-symbol in
% superscript ($\dagger$).
%
% \DescribeMacro{\video}
% This macro will create a video box on the current slide.
% Of course a video box can cover the entire slide if desired.
% 
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\video<overlay-spec>[options] (nodename) \at (x,y) { filename }|
% \item insert mode:\\
% \hspace*{2ex}|\video<overlay-spec>[options] (nodename) { filename }|
% \end{itemize}
%%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the video is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|width|] the width of the video box (a fraction relative to
% the width of the slide)
% \item[|height|] the height of the video box (a fraction relative
% to the height of the slide)
% \item[|aspectratio|] the aspectratio of the video box
% \end{options}
% Remember that you never specify both |width| and |height|, only one of
% those two in combination with the |aspectratio|.
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the video is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|$^\dagger$] synonym to |anchor=south|
% \item[|below|$^\dagger$] synonym to |anchor=north|
% \item[|left|$^\dagger$] synonym to |anchor=east|
% \item[|right|$^\dagger$] synonym to |anchor=west|
% \item[|above left|$^\dagger$] synonym to |anchor=south east|
% \item[|above right|$^\dagger$] synonym to |anchor=south west|
% \item[|below left|$^\dagger$] synonym to |anchor=north east|
% \item[|below right|$^\dagger$] synonym to |anchor=north west|
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|fit|] the way the video should occupy the box: |fill|,
% |cover| or |fit|
% \item[|background|] the color of the background of the box
% \item[|draw|$^\dagger$] generates an outline around the box that allows you
% to inspect where the video will end up in your PDF-file
% \item[|autoplay|$^\dagger$] causes the video to start playing a soon as it
% appears on the slide
% \item[|controls|$^\dagger$] causes player controls to appear below your video
% \item[|muted|$^\dagger$] silences the audio of the player
% \end{options}
% \paragraph{Various options (only one for now):}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|embed|$^\dagger$] causes the content of the video-file to be embedded
% as a Base64-encoded ASCII string in the main html file the script produces.
% I don't recommend this for video files.
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the video, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|filename|] a filename or URL that leads to the video file
% (e.g. an mp4 file). Any file playable by your browser will work.
% \end{arguments}
%
% Note that you can pause and (re)start your video by pressing 'v' when presenting
% your slide deck.
%
% \DescribeMacro{\audio}
% This macro will create an audio block on the current slide. This
% block is rather an abstract concept, unless you activate the
% controls of the player. Indeed, the audio block will be invisible
% unless you specify the option to display the controls of the player. 
%
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\audio<overlay-spec>[options] (nodename) \at (x,y) { filename }|
% \item insert mode:\\
% \hspace*{2ex}|\audio<overlay-spec>[options] (nodename) { filename }|
% \end{itemize}
%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the audio is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|width|] the width of the audio box (a fraction relative to
% the width of the slide)
% \item[|height|] the height of the audio box (a fraction relative
% to the height of the slide)
% \item[|aspectratio|] the aspectratio of the audio box
% \end{options}
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the audio box is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|$^\dagger$] synonym to |anchor=south|
% \item[|below|$^\dagger$] synonym to |anchor=north|
% \item[|left|$^\dagger$] synonym to |anchor=east|
% \item[|right|$^\dagger$] synonym to |anchor=west|
% \item[|above left|$^\dagger$] synonym to |anchor=south east|
% \item[|above right|$^\dagger$] synonym to |anchor=south west|
% \item[|below left|$^\dagger$] synonym to |anchor=north east|
% \item[|below right|$^\dagger$] synonym to |anchor=north west|
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|fit|] the way the audio block should occupy the box: |fill|,
% |cover| or |fit|
% \item[|background|] the color of the background of the box
% \item[|draw|$^\dagger$] generates an outline around the box that allows you
% to inspect where the audio box will end up in your PDF-file
% \item[|autoplay|$^\dagger$] causes the audio to start playing a soon as it
% appears on the slide
% \item[|controls|$^\dagger$] causes player controls to appear
% \item[|muted|$^\dagger$] silences the audio of the player
% \end{options}
% \paragraph{Various options (only one for now):}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|embed|$^\dagger$] causes the content of the audio-file to be embedded
% as a Base64-encoded ASCII string in the main html file the script produces.
% I don't recommend this for audio files.
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the audio, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|filename|] a filename or URL that leads to the audio file
% (e.g. an mp3 or ogg vorbis file). Any file playable by your browser will work.
% \end{arguments}
%
% Note that you can pause and (re)start your audio fragment by pressing 'a' when presenting
% your slide deck.
%
% \DescribeMacro{\iframe}
% This macro will create an iframe box on the current slide.
% Of course an iframe box can cover the entire slide if desired.
% 
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\iframe<overlay-spec>[options] (nodename) \at (x,y) { filename }|
% \item insert mode:\\
% \hspace*{2ex}|\iframe<overlay-spec>[options] (nodename) { filename }|
% \end{itemize}
%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the iframe is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|width|] the width of the iframe box (a fraction relative to
% the width of the slide)
% \item[|height|] the height of the iframe box (a fraction relative
% to the height of the slide)
% \item[|aspectratio|] the aspectratio of the iframe box
% \end{options}
% Remember that you never specify both |width| and |height|, only one of
% those two in combination with the |aspectratio|.
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the video is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|] synonym to |anchor=south|;
% \item[|below|] synonym to |anchor=north|;
% \item[|left|$^\dagger$] synonym to |anchor=east|;
% \item[|right|$^\dagger$] synonym to |anchor=west|;
% \item[|above left|$^\dagger$] synonym to |anchor=south east|;
% \item[|above right|$^\dagger$] synonym to |anchor=south west|;
% \item[|below left|$^\dagger$] synonym to |anchor=north east|;
% \item[|below right|$^\dagger$] synonym to |anchor=north west|;
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|fit|] the way the iframe should occupy the box: |fill|,
% |cover| or |fit|
% \item[|background|] the color of the background of the box
% \item[|draw|] generates an outline around the box that allows you
% to inspect where the iframe will end up in your PDF-file;\footnotemark[\value{footnote}]
% \end{options}
% \paragraph{Various options (only one for now):}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|embed|$^\dagger$] causes the content of the iframe html-file to be embedded
% as a Base64-encoded ASCII string in the main html file the script produces.
% For iframe material, I think this makes sense if you want to avoid using an
% auxiliary webbrowser (e.g. if your are presenting using someone else's computer).
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the iframe, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|filename|] a filename or URL that leads to the iframe content
% (e.g. an HTML file generated by asymptote). Note that for the content to work,
% you might need to serve your presentation through a local html server:\\
% |$ python -m http.server|
% \end{arguments}
%
% \DescribeMacro{\image}
% This macro will create an image box on the current slide.
% Of course an image box can cover the entire slide if desired.
%
% Note that using the |\includegraphics| command of the |graphicx|
% package is still preferred to include the standard image formats,
% such as PDF, PNG, TIFF and JPG. However, the |image| command also
% allows to include (animated) GIFs, webp and SVG files.
%
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\image<overlay-spec>[options] (nodename) \at (x,y) { filename }|
% \item insert mode:\\
% \hspace*{2ex}|\image<overlay-spec>[options] (nodename) { filename }|
% \end{itemize}
%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the image is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|width|] the width of the image box (a fraction relative to
% the width of the slide)
% \item[|height|] the height of the image box (a fraction relative
% to the height of the slide)
% \item[|aspectratio|] the aspectratio of the image box
% \end{options}
% Remember that you never specify both |width| and |height|, only one of
% those two in combination with the |aspectratio|.
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the image is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|$^\dagger$] synonym to |anchor=south|;
% \item[|below|$^\dagger$] synonym to |anchor=north|;
% \item[|left|$^\dagger$] synonym to |anchor=east|;
% \item[|right|$^\dagger$] synonym to |anchor=west|;
% \item[|above left|$^\dagger$] synonym to |anchor=south east|;
% \item[|above right|$^\dagger$] synonym to |anchor=south west|;
% \item[|below left|$^\dagger$] synonym to |anchor=north east|;
% \item[|below right|$^\dagger$] synonym to |anchor=north west|;
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|fit|] the way the image should occupy the box: |fill|,
% |cover| or |fit|
% \item[|background|] the color of the background of the box
% \item[|draw|] generates an outline around the box that allows you
% to inspect where the image will end up in your PDF-file;\footnotemark[\value{footnote}]
% \end{options}
% \paragraph{Various options (only one for now):}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|embed|$^\dagger$] causes the content of the image-file to be embedded
% as a Base64-encoded ASCII string in the main html file the script produces.
% I don't recommend this for image files.
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the image, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|filename|] a filename or URL of the image file
% (e.g. a GIF file).
% \end{arguments}
%
% \DescribeMacro{\animation}
% This macro will create an animation box on the current slide.
% Different from the other boxes, this box will determine its own width and
% height, based on the dimensions of the LaTeX content embedded in it.
% In fact, it is illegal to specify aspectratio, width or height.
%
% The animation is generated as follows: the content of macro will be
% written by the |beamer-reveal.pl| script
% to a separate LaTeX file using the |standalone| class.
% The preamble that it uses will be the part of the preamble in your
% beamer source file, in between the loading of the |beamer-reveal| package
% and the line containing |\begin{document}|. The animation block will be
% embedded in a loop that will be executed |duration| $\cdot$
% |framerate| times, providing a macro |\progress| that contains a
% fraction that goes up from $0$ (first iteration) to $1$ last
% iteration. The PDF-file that is generated with this standalone file,
% is converted to an mp4-file that is included as a video on your
% slide.\\
% The tools used for this are the \LaTeX{}-compiler you used for your beamer sourcefile,
% |pdfcrop| \cite{pdfcrop}, |pdftoppm| \cite{pdftoppm} and |ffmpeg| \cite{ffmpeg}.
% 
% This animation generation takes advantage of the multicore nature of
% your computer, by simple, but smart parallelization (on
% non-MS-Windows operating systems).
%
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\animation<overlay-spec>[options] (nodename) \at (x,y) { content }|
% \item insert mode:\\
% \hspace*{2ex}|\animation<overlay-spec>[options] (nodename) { content }|
% \end{itemize}
%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the animation is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:} no size options; size is determined from
% the \LaTeX{} code itself!
% \paragraph{Generation options:}
% \begin{options}
% \item[|framerate|] number of frames per second that the animation
% should contain.
% \item[|duration|] duration (in seconds) of the animation
% \item[|pdf progress|] value that the progress macro will take on when
% a picture of the animation frame is made in your PDF-file.
% \item[|handout progress|] comma separated list of 'handout number' ':' 'progress value'
% that specifies which progress value to use on which handout number.
% This assumes that the overlay-spec of the |\animation| macro also specifies to generate
% the required handout slide numbers. Take a look at the example in this manual for more
% clarity on this.
% \item[|expand once|] will cause the content to be expanded once; use
% this if you described your animation in a macro and want to expand that macro.
% \end{options}
% The number of frames that will be generated for the animation is:
% \begin{align}
%    \texttt{number-of-frames} = \texttt{framerate} \cdot \texttt{duration}
% \end{align}
% Your PDF file will contain a single shot of the animation (as if it
% were a preview shot). For this frame, the value of the |\progress|
% macro will be set to |pdf progress|.
%
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the animation is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|$^\dagger$] synonym to |anchor=south|
% \item[|below|$^\dagger$] synonym to |anchor=north|
% \item[|left|$^\dagger$] synonym to |anchor=east|
% \item[|right|$^\dagger$] synonym to |anchor=west|
% \item[|above left|$^\dagger$] synonym to |anchor=south east|
% \item[|above right|$^\dagger$] synonym to |anchor=south west|
% \item[|below left|$^\dagger$] synonym to |anchor=north east|
% \item[|below right|$^\dagger$] synonym to |anchor=north west|
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|background|] the color of the background of the box
% \item[|draw|$^\dagger$] generates an outline around the box that allows you
% to inspect where the video will end up in your PDF-file
% \item[|autoplay|$^\dagger$] causes the video to start playing a soon as it
% appears on the slide
% \item[|controls|$^\dagger$] causes player controls to appear below your video
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the animation, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|content|] the LaTeX code that generates every
% frame based on the |\progress| 'time variable'. Any macros used in
% this content need to be defined in the content itself or in the
% preamble of your slide deck in between the
% |\usepackage{beamer-reveal}| and the |\begin{document}| as this
% portion is also used when generation the animation. If that is not
% the case, you can specify an extra option |expand once| to perform a
% single expansion, such that the macros and environments on the top
% level are expanded once. The example contained in this manual shows
% you an example of this.
% \end{arguments}
%
% Note that you can pause and (re)start your animation fragment by
% pressing 'v' (as it is in fact a video)  when presenting your slide
% deck. 
%
% \DescribeMacro{\still}
% This macro will create the still (of an animation) box on the current slide.
% The idea is that you can split your animation in parts and separate these parts
% with a slide (or a subframe, if you are using multiple overlays)
% containing a still corresponding to the point between the animation
% parts. Just as the animation box, this box will determine its own width and
% height, based on the dimensions of the LaTeX content embedded in it.
% In fact, it is illegal to specify aspectratio, width or height.
% 
% The still is generated as follows: the content of macro will be
% written by the |beamer-reveal.pl| script
% to a separate LaTeX file using the |standalone| class.
% The preamble that it uses will be the part of the preamble in your
% beamer source file, in between the loading of the |beamer-reveal| package
% and the line containing |\begin{document}|. The animation block will be
% embedded in an environment that sets the macro |\progress| to a value
% in between $0$ and $1$. The PDF-file that is generated with this standalone file,
% is converted to a jpg-file that is included as a still image on your
% slide.\\
% The tools used for this are the \LaTeX{}-compiler you used for your beamer sourcefile,
% |pdfcrop| \cite{pdfcrop} and |pdftoppm| \cite{pdftoppm}.
% 
% Its syntax is:
% \begin{itemize}
% \item overlay mode:\\
% \hspace*{2ex}|\still<overlay-spec>[options] (nodename) \at (x,y) { content }|
% \item insert mode:\\
% \hspace*{2ex}|\still<overlay-spec>[options] (nodename) { content }|
% \end{itemize}
%
% The arguments are:
% \begin{arguments}
% \item[|overlay-spec|] a standard beamer overlay specification that
% allows you to determine on which overlays the still is to appear;
% this argument will end up in a traditional |\only<>{}| clause that
% beamer provides.
% \item[|options|] the following keys are available. In general they
% require a value: |key=value|.
% \paragraph{Size options:} no size options; size is determined from
% the \LaTeX{} code itself!
% \paragraph{Generation options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|pdf progress|] value that the progress macro will take.
% \item[|expand once|] will cause the content to be expanded once; use
% this if you described your still in a macro and want to expand that macro.
% \end{options}
% Your PDF file will contain the image typeset by your LaTeX{} run.
% In the reveal version of the presentation, the image will be overlaid
% by the generated still, such that it aligns perfectly with a corresponding video
% on an adjacent slide.
% \paragraph{Placement options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|anchor|] value is one of |center|, |north|, |west|, |south|, |east|,
% |north east|, |north west|, |south east|, |south west|; this
% specifies where the anchor of the animation is positioned; the anchor
% will be positioned at |(x,y)|
% \item[|above|$^\dagger$] synonym to |anchor=south|
% \item[|below|$^\dagger$] synonym to |anchor=north|
% \item[|left|$^\dagger$] synonym to |anchor=east|
% \item[|right|$^\dagger$] synonym to |anchor=west|
% \item[|above left|$^\dagger$] synonym to |anchor=south east|
% \item[|above right|$^\dagger$] synonym to |anchor=south west|
% \item[|below left|$^\dagger$] synonym to |anchor=north east|
% \item[|below right|$^\dagger$] synonym to |anchor=north west|
% \end{options}
% \paragraph{Appearance options:}\mbox{}\\*[-2ex]
% \begin{options}
% \item[|background|] the color of the background of the box
% \item[|draw|$^\dagger$] generates an outline around the box that allows you
% to inspect where the video will end up in your PDF-file
% \end{options}
% \item[|nodename|] (optional) name to assign to the rectangular node corresponding to the bounding box of the animation, such that you can later refer to that node
% (and its derived anchors (e.g. as '|(nodename.south)|') to position other material.
% \item[|x|, |y|] the $x$- and $y$-coordinate of the box, specified as a
% fraction of the slide width and slide height (dimensionless), fixing
% the anchor of the box, w.r.t. the bottom left of your slide.
% \item[|animation-LaTeX-content|] the LaTeX code that generates every
% frame based on the |\progress| 'time variable'. Any macros used in
% this content need to be defined in the content itself or in the
% preamble of your slide deck in between the
% |\usepackage{beamer-reveal}| and the |\begin{document}| as this
% portion is also used when generation the still. If that is not
% the case, you can specify an extra option |expand once| to perform a
% single expansion, such that the macros and environments on the top
% level are expanded once. The example contained in this manual shows
% you an example of this.  
% \end{arguments}
%
% \subsection{Short overview of the options for the different media macros} 
% Most of the macros have very similar options, but some are not
% common to all of them. Therefore, I made a small overview. I admit,
% mostly to help myself to keep the overview while developing the
% package.
% \begin{table}[p]
% \newcommand\ok{$\bullet$}
% \newcommand\nok{$\times$}
% \centering
% \begin{sideways}
% \begin{minipage}{25cm}
% \footnotesize
% \centering
% \renewcommand\arraystretch{1.5}
% \begin{tabular}{lcccccccccccccc}
% \toprule
%           & \bf Size & \bf Placement & 
%           \multicolumn{6}{c}{\bf Appearance} &
%           \bf Various &
%           \multicolumn{5}{c}{\bf Generation} \\
% \cmidrule(lr){2-2}
% \cmidrule(lr){3-3}
% \cmidrule(lr){4-9}
% \cmidrule(lr){10-10}
% \cmidrule(lr){11-15}
% \bf Macro & \footnotesize |w| / |h| / |ar| & |anchor| &
% |fit| & |background| & |draw| & |autoplay| & |controls| & |muted| &
% |embed| &
% |framerate| & |duration| & |pdf progress| & |handout progress| &
% |expand once|\\
% \midrule
% |\video|     & \ok$^1$ & \ok & \ok & \ok & \ok & \ok  & \ok  & \ok &
% \ok & \nok & \nok & \nok & \nok & \nok \\
% |\audio|     & \ok$^1$ & \ok & \ok & \ok & \ok & \ok  & \ok  & \ok & 
% \ok & \nok & \nok & \nok & \nok & \nok \\
% |\iframe|    & \ok$^1$ & \ok & \ok & \ok & \ok & \nok & \nok & \nok& 
% \ok & \nok & \nok & \nok & \nok & \nok \\
% |\image|     & \ok$^1$ & \ok & \ok & \ok & \ok & \nok & \nok & \nok& 
% \ok & \nok & \nok & \nok & \nok & \nok \\
% |\animation| & \nok    & \ok & \ok & \ok & \ok & \ok  & \ok  & \nok& 
% \ok & \ok & \ok & \ok & \ok & \ok \\
% |\still|     & \nok    & \ok & \ok & \ok & \ok & \nok & \nok & \nok& 
% \ok & \nok & \nok & \ok & \nok & \ok \\
% \bottomrule
% \end{tabular}\\~\\
% $^1$ |aspectratio| and |width|, or |aspectratio| and |height|, never
% |width| and |height| together
% \end{minipage}
% \end{sideways}
% \end{table}
% 
% \clearpage
%
% \newgeometry{left=1.75cm,right=1.75cm,top=2cm,bottom=2.5cm}
%
% \section{Example}
%
% \subsection{Using the example}
% An example will allow you to get an idea of the convenience of the package.
% The following steps will allow you to observe it in your browser:
%
% |$ lualatex beamer-reveal-example.tex|\\
% |$ beamer-reveal.pl beamer-reveal-example|\\
% |$ python -m http.server|
%
% Then open in your browser: \url{localhost:8000} and enjoy!
%
% \subsection{The source code of the example}
% \begin{verbatim}
%<*example> 
\documentclass[11pt,aspectratio=169,t]{beamer}%
\setbeamertemplate{navigation symbols}{}

\usepackage[width=1920,embed,autoslide=4000,loop]{beamer-reveal}
\usepackage{tikz}
\usepackage{siunitx}

\newcommand\eu{\mathrm{e}}
\newcommand\ju{\mathrm{j}}

\title{Test slide deck}
\subtitle{\textsc{beamer-reveal}}
\author{Walter Daems}

\setbeamertemplate{note page}{\insertnote}

\begin{document}

\begin{frame}[titleslide]
  \titlepage
\end{frame}

\AtBeginSection{
  \begin{frame}[sectionslide]{Overview}
    \tableofcontents[currentsection]
  \end{frame}
}
\AtBeginSubsection{
  \begin{frame}[subsectionslide]{Overview}
    \tableofcontents[currentsection,currentsubsection]
  \end{frame}
}

\section{Introduction}
\subsection{Slide making}

\begin{frame}
  {Good news}
  {}
  You can keep on making your slides the way you are used to!
  \begin{itemize}
  \item all the nice \LaTeX{} stuff at your fingertips
  \item no tempation to use too much unnecessary animation
  \end{itemize}
  \bigskip

  Indeed, there are no tools that can typeset equations like the tools form the \TeX-ecosystem:
  \begin{equation}
    \eu^{-\ju\pi}+1=0
  \end{equation}

  \note[item]{Make joke about fingertips}
  \note[item]{Don't speak about your personal temptations!}
\end{frame}

\begin{frame}[transition=concave,embed,autoslide=2000] 
  {Pr\^et-\`a-porter}
  {A dummy slide}
  \vfill
  Showing off the 'concave' slide transition animation. Not recommended!
  \vfill
\end{frame}

\begin{frame}[transition=convex]
  {Très chique}
  {A dummy slide}
  \vfill
  Showing off the 'convex' slide transition animation. Not recommended!
  \vfill
\end{frame}

\subsection{Pimping your slides}

\begin{frame}
  {And even more good news}
  {\ldots almost seems to good to be true\ldots}
  \small
  However, now you can pimp your slides like never before. You can incorporate:
  \begin{itemize}
  \item videos and audio fragments
  \item animated GIFs and LaTeX animations
  \item iframe content
  \end{itemize}
  without being tied to Acrobat reader.
  In addition, there are some extra features
  \begin{itemize}
  \item press '?' for keyboard help, amongst which you will find:
  \item press 'm' to open the slide menu on the left
  \item press 'o' to get an overview of the slides
  \item press 's' to start a speaker view
  \item press 'g' to go to a specific slide by typing its slide number
  \end{itemize}
  The pancake menu on the bottom left also opens the menu.
\end{frame}

\note{
  Don't spend too much time on this slide
}

\begin{frame}[transition=zoom]
  {A dymmy slide}
  {number three}
  \vfill
  Showing off the 'zoom slide transition animation. Not recommended!
  \vfill
\end{frame}

\section{In detail}

\subsection{Candy for the eye}

\begin{frame}
  {Placing videos}
  {}
  \only<1>{On this first slide there is nothing to see. On the next animation frame, a video will appear.}
  \only<2>{Here it is!}
  \video<2>[above,draw,autoplay,height=0.7,aspectratio=16/9,
            background=yellow,fit=contain]
  (myvid) \at (0.5,0.1) {Media/beamer-reveal-testvideo.mp4}
  \tikz[remember picture,overlay] \node<2>[anchor=north,font=\tiny] at (myvid.south)
       {An example video (C) Walter Daems};
\end{frame}

\begin{frame}
  {Placing images (possibly animated)}
  {}
  \begin{columns}
    \column[T]{0.45\textwidth}
    Below you will find a png (for which you don't need reveal, BTW).
    \vspace*{1cm}

    Of course, you can exploit the transparency of the background layer in the PNG!
    \vspace*{2cm}
    
    And on the top right you will find a swinging pendulum (an animated GIF).
    \column[T]{0.45\textwidth}
    % this is a image whose box consumes area on your slide
    \image[width=0.33,aspectratio=1,fit=contain,draw] (myimage) {Media/beamer-reveal-AnimatedPendulum.gif}
  \end{columns}
  % this is an overlayed image (not consuming any space)
  \image[width=0.25,aspectratio=1,fit=contain] \at (0.1,0.6) {Media/beamer-reveal-WiresTp.png}
\end{frame}

\begin{frame}
  {Placing iframe material (possibly animated)}
  {e.g. generated with asymptote}

  Click and drag on the iframe below. You can manipulate it! Use your mouse
  scroll-wheel to zoom in or out.
  \iframe[draw,anchor=north,height=0.6,aspectratio=16/9,embed,
          fit=cover] \at (0.5,0.7) {Media/beamer-reveal-PCB.html}
\end{frame}

\note{
  Don't mention the amount of hours that went into this iframe!
}

\subsection{Resonance for the ear}

\begin{frame}
  {Adding audio to your slides}
  {}
  Below, there is an audio block
  that automatically starts playing.\\
  \audio[autoplay,controls,width=0.1,aspectratio=16/9,
    background=blue,fit=cover] {Media/beamer-reveal-AudioSample.ogg}
\end{frame}

\subsection{Make (video) animations with LaTeX}

\newcommand\myanimation{%
      \begin{tikzpicture}[font=\footnotesize,transform shape,scale=0.75]
        \pgfmathsetmacro\angle{\progress*540}%
        \clip (-2,-5.25) rectangle (8,2);
        \node[below left,inner sep=1pt] at (0,0) {\tiny 0};
        \node[below left,inner sep=1pt] at (2.5,0) {\tiny 0};
        \node[above right,inner sep=1pt] at (0,-2) {\tiny 0};
        
        \begin{scope}[every node/.style={right}]
          \node[thick,draw,rectangle] at (2.5,-2)
               {\large $x(t) = A \cdot \eu^{j\omega t}$};
               \node at (3.5,-3)
                     {\large $\eu^{j\alpha} = \cos\alpha+j\sin\alpha$};
                     \node at (2.5,-4)
                           {\large $x(t) = \underbrace{A \cos \omega t}_{\text{\textcolor{orange}{real}}}
                             + \underbrace{j A \sin \omega t}_{\text{\textcolor{olive}{imaginary}}}$};
        \end{scope}
        \draw[->,thick] (3,-2.4) -- (3,-3.4);
        \draw[blue,thick] (0,0) circle (1);

        \draw[->] (-1.25,0) -- (1.25,0) node[below] {Re};
        \draw[->] (0,-1.25) -- (0,1.25) node[left] {Im};

        % circle
        \draw[olive,very thick] (0,0) -- (0,{sin(\angle)});
        \draw[orange,very thick] (0,0) -- ({cos(\angle)},0);
        \draw[blue,thick,->] (0,0) -- node[left,font=\tiny] {A} +(\angle:1);
        \draw[->] (0.4,0) arc (0:\angle:0.4);
        \node at (0.5*\angle:0.7) {\scriptsize $\omega \tilde t$};

        % right graph
        \draw[very thick,olive] ({2.5+\angle/180},0) -- +(0,{sin(\angle)});
        \draw[densely dotted] ({min(0,cos(\angle))},{sin(\angle)})
        -- ({2.5+\angle/180},{sin(\angle)});
        \draw[thick] ({2.5+\angle/180},0) +(0,1pt) -- +(0,-1pt) node[below] {$\tilde t$};

        % bottom graph
        \draw[very thick,orange] (0,{-2-\angle/180}) -- +({cos(\angle)},0);
        \draw[densely dotted] ({cos(\angle)},{max(0,sin(\angle))})
        -- ({cos(\angle)},{-2-\angle/180});
        \draw[thick] (0,{-2-\angle/180}) +(1pt,0) -- +(-1pt,0) node[left] {$\tilde t$};

        % right graph
        \foreach \y/\l in {-1/-A,1/A} {
          \draw[gray,densely dotted] (2.5,\y) -- (6.25,\y);
          \draw (2.5,\y) +(+1pt,0) -- +(-1pt,0) node[left] {$\l$};
        }
        \draw[->] (2.0,0) -- (6.5,0) node[below] {$t$};
        \draw[->] (2.5,-1.25) -- (2.5,1.25) node[left] {$Im(x(t))$};
        \draw[olive,thick,domain=-0.25:3.5,samples=30,smooth] plot
        ({\x+2.5},{sin(pi*\x r)});

        % bottom graph
        \foreach \y/\l in {-1/-A,1/A} {
          \draw[gray,densely dotted] (\y,-2) -- (\y,-4.5);
          \draw (2.5,\y) +(+1pt,0) -- +(-1pt,0) node[left] {$\l$};
        }
        \draw[->] (-1.25,-2) -- (1.25,-2) node[above] {$Re(x(t))$};
        \draw[->] (0,-1.5) -- (0,-5) node[left] {$t$};

        \draw[orange,thick,domain=-0.25:2.6,samples=30,smooth] plot
        ({cos(pi*\x r)},{-2-\x});
      \end{tikzpicture}%
}

\begin{frame}
  {Making animations with LaTeX (using TikZ as example)}
  {It is easier than ever before}
  \small The animation content is exported to a standalone \LaTeX-document that creates a
  loop over it, for a \texttt{duration} seconds at
  \texttt{framerate} frames per second providing a \texttt{\textbackslash{}progress}
  variable that goes gradually from 0 to 1 in \texttt{duration} $\times$
  \texttt{framerate} frames. The beamer-reveal.pl script transforms it
  to mp4 maximally exploiting your multi-core CPU.

  \begin{center}
    \animation<1|handout:1-3>[framerate=25,duration=7.5,autoplay,
      pdf progress=0.1,handout progress={1:0,2:0.2,3:0.5},expand once] {\myanimation}
  \end{center}
\end{frame}

\begin{frame}
  {Making animations with LaTeX (using TikZ as example)}
  {Another slide with just a 'still' - but with some music!}
  \small The animation content is exported to a standalone \LaTeX-document that creates a
  loop over it, for a \texttt{duration} seconds at
  \texttt{framerate} frames per second providing a \texttt{\textbackslash{}progress}
  variable that goes gradually from 0 to 1 in \texttt{duration} $\times$
  \texttt{framerate} frames. The beamer-reveal.pl script transforms it
  to mp4 maximally exploiting your multi-core CPU.

  \begin{center}
    \still[pdf progress=0.75,expand once] {\myanimation}
  \end{center}
  \audio[width=0.1,aspectratio=16/9,fit=cover,autoplay] \at (0,0)
        {Media/beamer-reveal-AudioSample.ogg}        
\end{frame}

\end{document}
%</example> 
% \end{verbatim}
% \clearpage
%
% \StopEventually{\PrintChanges\PrintIndex}
%
% \section{Implementation}
%
% \subsection{The preamble of the package}
%
%    \begin{macrocode}
%<*reveal>
\ExplSyntaxOn
\tl_new:N \g_@@_fileversion_tl
\tl_set:Nn \g_@@_fileversion_tl {v1.08}
\tl_new:N \g_@@_filedate_tl
\tl_set:Nn \g_@@_filedate_tl {2026-02-04}
\RequirePackage{l3keys2e}
%</reveal>
%    \end{macrocode}
%
% \subsection{Error/warning messages}
%
%    \begin{macrocode}
%<*reveal>
\msg_new:nnn{ beamer-reveal } { inconsistent-dimensions } {
  aspect~ratio~of~beamer~(#1)~and~reveal~(#2:#3)~are~not~consistent.\\
  You~must~specify~consistent~values~for~width/height~and~aspectratio~
  otherwise~your~reveal~items~(videos/images/animations)~will~not~appear~
  on~the~right~locations~on~your~reveal-slidedeck.
}
\msg_new:nnn{ beamer-reveal } { missing-aspectratio } {
  missing~aspect~ratio.\\
  You~need~to~specify~at~least~an~aspect~ratio~for~a~beamer-reveal~item~
  you~want~to~put~on~the~reveal~slide.
}
\msg_new:nnn{ beamer-reveal } { missing-width-or-height } {
  missing~width~or~height.\\
  You~need~to~specify~at~least~a~width~or~a~height~for~a~beamer-reveal~item~
  you~want~to~put~on~the~reveal~slide.
}
\msg_new:nnn{ beamer-reveal } { overconstrained-box } {
  overconstrained~box.\\
  You~cannot~both~specify~the~width~and~the~height~of~a~beamer-reveal~item~
  you~want~to~put~on~the~slide.
  Specify~width~and~aspectratio~or~height~and~aspectratio.
}
\msg_new:nnn{ beamer-reveal } { dynamic-option-for-staticcontent } {
  dynamic~option~given~(autoplay,~controls,~loop,~muted)~for~static~
  content~(\image,~\iframe).\\
  These~options~make~no~sense~for~the~\image~command.~Remove~them.
}
\msg_new:nnn{ beamer-reveal } { animation-option-for-nonanimation } {
  duration~and~framerate~are~options~that~can~only~be~given~for~the~
  \animation~command.\\
  Remove~them~from~the~\video,~\audio,~\image~and~\iframe~commands.
}
\msg_new:nnn { beamerreveal / Syntax } { missing-coordinate }
    { you~specified~'\c_backslash_str at'~but~gave~no~coordinate. }
\msg_new:nnn { beamerreveal / Syntax } { old-at-syntax }
    { I~choked~on~'a';~note~that~the~syntax~has~changed:~replace~'at'~with~'\c_backslash_str at'. }
\msg_new:nnn { beamerreveal / Syntax } { missing-at }
    { you~specified~a~coordinate~but~not~an~'\c_backslash_str at'~token;~did~you~forget~that? }
%</reveal>
%    \end{macrocode}
%
% \subsection{Some pdflatex backwards compatibility}
%
%    \begin{macrocode}
%<*reveal>
\@ifundefined{pagewidth}{%
  \let\pagewidth\pdfpagewidth
  \let\pageheight\pdfpageheight
}{}
%</reveal>
%    \end{macrocode}
%
%
%
% \subsection{Package options}
% First some global variables to store the global width and height of
% the presentation, that can be specified as package options:
%    \begin{macrocode}
%<*reveal>
\tl_new:N \g_@@_beameraspectratio_tl
\tl_set:Nn \g_@@_beameraspectratio_tl {43}
\fp_new:N \g_@@_canvaswidth_fp
\fp_set:Nn \g_@@_canvaswidth_fp { \dim_to_fp:n {\paperwidth} }
\fp_new:N \g_@@_canvasheight_fp
\fp_set:Nn \g_@@_canvasheight_fp { \dim_to_fp:n {\paperheight} }
\fp_new:N \g_@@_canvasaspectratio_fp
\fp_set:Nn \g_@@_canvasaspectratio_fp { \g_@@_canvaswidth_fp / \g_@@_canvasheight_fp }
\int_new:N \g_@@_canvaswidth_int
\int_set:Nn \g_@@_canvaswidth_int {0}
\int_new:N \g_@@_canvasheight_int
\int_set:Nn \g_@@_canvasheight_int {0}
\bool_new:N \g_@@_embed_bool
\bool_set:Nn \g_@@_embed_bool { \c_false_bool }
\bool_new:N \g_@@_loop_bool
\bool_set:Nn \g_@@_loop_bool { \c_false_bool }
\int_new:N \g_@@_autoslide_int
\int_set:Nn \g_@@_autoslide_int { 0 }
\keys_define:nn { beamerreveal } {
  width     .int_set:N        = \g_@@_canvaswidth_int,
  width     .value_required:n = true,
  height    .int_set:N        = \g_@@_canvasheight_int,
  height    .value_required:n = true,
  embed     .bool_set:N       = \g_@@_embed_bool,
  loop      .bool_set:N       = \g_@@_loop_bool,
  autoslide .int_set:N        = \g_@@_autoslide_int,
  autoslide .value_required:n = true,
}
\ProcessKeyOptions[beamerreveal]
\int_compare:nNnTF { \g_@@_canvaswidth_int } = {0}
    {
      \int_compare:nNnTF { \g_@@_canvasheight_int } = {0}
          {
            % we assume 4x3 on an HD screen
            \int_set:Nn \g_@@_canvaswidth_int { 1920 }
            \int_set:Nn \g_@@_canvasheight_int
                { \fp_eval:n { round( \g_@@_canvaswidth_int / \g_@@_canvasaspectratio_fp ) } }
          }
          {
            % we assume 4x3
            \int_set:Nn \g_@@_canvaswidth_int
                { \fp_eval:n { round( \g_@@_canvasheight_int * \g_@@_canvasaspectratio_fp ) } }
          }
    }
    {
      \int_compare:nNnTF { \g_@@_canvasheight_int } = {0}
          {
            % we assume 4x3 on an HD screen
            \int_set:Nn \g_@@_canvasheight_int{ \fp_eval:n
              { round( \g_@@_canvaswidth_int / \g_@@_canvasaspectratio_fp ) } }
          }
          {
            % both are set, we're good to go
            \fp_new:N \l_@@_canvasaspectratioresidue_fp
            \fp_set:Nn \l_@@_canvasaspectratioresidue_fp
               { \fp_abs:n { \g_@@_canvaswidth_int / \g_@@_canvasheight_int - \g_@@_canvasaspectratio_fp } }
            \fp_compare:nNnTF { \l_@@_canvasaspectratioresidue_fp } > {0.001}
               {
                 \msg_warning:nneee { beamer-reveal } { inconsistent-dimensions }
                     { \tl_use:N \g_@@_beameraspectratio_tl }
                     { \int_use:N \g_@@_canvaswidth_int }
                     { \int_use:N \g_@@_canvasheight_int }
               }{}
          }
    }
%</reveal>
%    \end{macrocode}
    
% \subsection{Extra options for the frame environment of \beamer{}}
%
%    \begin{macrocode}
%<*reveal>
\bool_new:N \g_@@_titlepage_bool
\define@key{beamerframe}{titleslide}[true]{%
  \ExplSyntaxOn
  \bool_gset_true:N \g_@@_titlepage_bool
  \ExplSyntaxOff
}
\bool_new:N \g_@@_sectionslide_bool
\define@key{beamerframe}{sectionslide}[true]{%
  \ExplSyntaxOn
  \bool_gset_true:N \g_@@_sectionslide_bool
  \ExplSyntaxOff
}
\bool_new:N \g_@@_subsectionslide_bool
\define@key{beamerframe}{subsectionslide}[true]{%
  \ExplSyntaxOn
  \bool_gset_true:N \g_@@_subsectionslide_bool
  \ExplSyntaxOff
}
\tl_new:N \g_@@_transition_tl
\define@key{beamerframe}{transition}[none]{%
  \ExplSyntaxOn
  \tl_gset:Nn \g_@@_transition_tl { #1 }
  \ExplSyntaxOff
}
\define@key{beamerframe}{embed}[true]{%
  \ExplSyntaxOn
  \bool_gset_true:N \g_@@_embed_bool
  \ExplSyntaxOff
}
\define@key{beamerframe}{autoslide}[0]{%
  \ExplSyntaxOn
  \int_if_zero:nTF { #1 }{}{ \int_set:Nn \g_@@_autoslide_int {#1} }
  \ExplSyntaxOff
}
%</reveal>
%    \end{macrocode}
%
% \subsection{File writing}
% File handles and auxiliary functions to write data to the |.rvl|
% file.
%
%    \begin{macrocode}
%<*reveal>
\iow_new:N \g_@@_rvlfile
\iow_open:Nn \g_@@_rvlfile {\jobname.rvl}
%</reveal>
%    \end{macrocode}
%
% \begin{macro}{\writecomment\_@@:n}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \writecomment_@@:n #1
   { \iow_now:Ne \g_@@_rvlfile {\c_percent_str\c_percent_str\c_space_tl #1} }
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writecontrol\_@@:n}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \writecontrol_@@:nn #1 #2
   { \iow_now:Ne \g_@@_rvlfile {@ @#1:~#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writeliteral\_@@:n}
%    \begin{macrocode}
\cs_new:Npn \writeliteral_@@:n #1
   { \iow_now:Nx \g_@@_rvlfile {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writeraw\_@@:n}
%    \begin{macrocode}
\cs_new:Npn \writeraw_@@:n #1
   { \iow_now:Nn \g_@@_rvlfile { #1 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\writeraw\_@@:n}
%    \begin{macrocode}
\cs_generate_variant:Nn \iow_now:Nn {No }
\cs_new:Npn \writeraw_@@:o #1
   { \iow_now:No \g_@@_rvlfile { #1 } }
%    \end{macrocode}
% \end{macro}
%
% Now initialize our \texttt{.rvl} file.
%   
%    \begin{macrocode}
\writecomment_@@:n {Beamer-reveal~driver~file~
  (\tl_use:N \g_@@_fileversion_tl - \tl_use:N \g_@@_filedate_tl)}  
\writecontrol_@@:nn {Presentation} {}
\tl_new:N \l_@@_my_compiler_tl
\tl_set:Nn \l_@@_my_compiler_tl { unknown }
\sys_if_engine_pdftex:T { \tl_set:Nn \l_@@_my_compiler_tl { pdflatex } }
\sys_if_engine_xetex:T  { \tl_set:Nn \l_@@_my_compiler_tl { xelatex } }
\sys_if_engine_luatex:T { \tl_set:Nn \l_@@_my_compiler_tl { lualatex } }
\AtBeginDocument{
  \writeliteral_@@:n {-parameters:
    sourcefilename={\currfilename},
    title={\inserttitle},
    author={\beamer@shortauthor},
    compiler={\tl_use:N \l_@@_my_compiler_tl },
    \bool_if:NT \g_@@_embed_bool {embed={},}
    \bool_if:NTF \g_@@_loop_bool {loop={true}}{loop={false}},
    autoslide={\int_use:N \g_@@_autoslide_int},
    canvaswidth={\int_use:N \g_@@_canvaswidth_int},
    canvasheight={\int_use:N \g_@@_canvasheight_int}
  }
}
%</reveal>
%    \end{macrocode}
%
% \subsection{Frame generation}
%
%    \begin{macrocode}
%<*reveal>
\AddToHook{ env / frame / begin} {
  \bool_gset_false:N \g_@@_titlepage_bool
  \bool_gset_false:N \g_@@_sectionslide_bool
  \bool_gset_false:N \g_@@_subsectionslide_bool
  \bool_gset_false:N \g_@@_embed_bool
  \int_gset:Nn \g_@@_autoslide_int {0}
  \tl_gset:Nn \g_@@_transition_tl {none}
}
\AddToHook{ env / beamer@frameslide / before} {
  \writecontrol_@@:nn {BeamerFrame} {}
}
\AddToHook{ env / beamer@frameslide / after} {
  \writeliteral_@@:n
               {-parameters:rawpage={\insertpagenumber},
                 truepage={\insertframenumber},
                 overlay={\insertoverlaynumber},
                 transition={\tl_use:N \g_@@_transition_tl},
                 \bool_if:NT \g_@@_embed_bool {embed={},}
                 \int_if_zero:nTF \g_@@_autoslide_int {}{autoslide={\int_use:N \g_@@_autoslide_int},}
                 \bool_if:NT \g_@@_embed_bool {embed={},}
                 \bool_if:NTF \g_@@_sectionslide_bool
                      {
                        title={\secname},toc={section}
                      }
                      {
                        \bool_if:NTF \g_@@_subsectionslide_bool
                             {
                               title={\subsecname},toc={subsection}
                             }
                             {
                               \bool_if:NTF \g_@@_titlepage_bool
                                    {
                                      title={\beamer@shorttitle},toc={titlepage}
                                    }
                                    {
                                      \sys_if_engine_pdftex:TF % avoid pdflatex screwing up old accents
                                          {title={\unexpanded\expandafter{\beamer@shortframetitle}}}
                                          {title={\beamer@shortframetitle}}
                                    }
                             }
                      }
               }
}
\AtBeginDocument {
  \AddToHook { cmd / note / before } {
    \writeliteral_@@:n
                 {-hasnote:true}
  }
}
%</reveal>
%    \end{macrocode}
%
% \subsection{Common keys for the macros}
%
%    \begin{macrocode}
%<*reveal>
\fp_new:N \l_@@_mediawidth_fp
\fp_new:N \l_@@_mediaheight_fp
\fp_new:N \l_@@_mediaframerate_fp
\fp_new:N \l_@@_mediaduration_fp
\fp_new:N \l_@@_mediapdfprogress_fp
\tl_new:N \l_@@_mediafit_tl
\tl_new:N \l_@@_mediabackground_tl
\tl_new:N \l_@@_mediahandoutprogress_tl
\fp_new:N \l_@@_xposdelta_fp
\fp_new:N \l_@@_yposdelta_fp
\bool_new:N \l_@@_mediaembed_bool
\bool_new:N \l_@@_mediaautoplay_bool
\bool_new:N \l_@@_medialoop_bool
\bool_new:N \l_@@_mediaboxdraw_bool
\bool_new:N \l_@@_mediamuted_bool
\bool_new:N \l_@@_mediacontrols_bool
\tl_new:N \l_@@_mediaanchor_tl
\bool_new:N \l_@@_mediaexpandonce_bool

\msg_new:nnn { beamerreveal / Syntax } { unknown-key }
{ Unknown~key~'#1'~for~media~(video,~animated,~...)~command. }
\msg_new:nnn { beamerreveal / Syntax } { illegal-keys-video }
{ Illegal~key(s)~'#1'~for~a~\video. }
\msg_new:nnn { beamerreveal / Syntax } { illegal-keys-image }
{ Illegal~key(s)~'#1'~for~an~\image. }
\msg_new:nnn { beamerreveal / Syntax } { illegal-keys-iframe }
{ Illegal~key(s)~'#1'~for~an~\iframe. }
\msg_new:nnn { beamerreveal / Syntax } { illegal-keys-animation }
{ Illegal~key(s)~'#1'~for~an~\animation. }
\msg_new:nnn { beamerreveal / Syntax } { key-syntax-changed }
{ The~syntax~of~the~key~of~'#1'~changed;~please~add~a~space~and~change~this~into~'#2'. }
\keys_define:nn { beamerreveal / media } {
  width .fp_set:N               = \l_@@_mediawidth_fp,
  width .value_required:n       = true,
  width .initial:n              = 0,
  width .groups:n               = { size },
  height .fp_set:N              = \l_@@_mediaheight_fp,
  height .value_required:n      = true,
  height .initial:n             = 0,
  height .groups:n              = { size },
  aspectratio .fp_set:N         = \l_@@_mediaaspectratio_fp,
  aspectratio .value_required:n = true,
  aspectratio .groups:n         = { size },
  fit .tl_set:N                 = \l_@@_mediafit_tl,
  fit .value_required:n         = true,
  fit .initial:n                = fill,
  fit .groups:n                 = { fit },
  background .tl_set:N          = \l_@@_mediabackground_tl,
  background .value_required:n  = true,
  background .initial:n         = white,
  background .groups:n          = { draw },
  draw .bool_set:N              = \l_@@_mediaboxdraw_bool,
  draw .initial:n               = false,
  draw .groups:n                = { draw },
  embed .bool_set:N             = \l_@@_mediaembed_bool,
  embed .initial:n              = false,
  autoplay .bool_set:N          = \l_@@_mediaautoplay_bool,
  autoplay .initial:n           = false,
  autoplay .groups:n            = { dynamic },
  loop .bool_set:N              = \l_@@_medialoop_bool,
  loop .initial:n               = false,
  loop .groups:n                = { dynamic },
  controls .bool_set:N          = \l_@@_mediacontrols_bool,
  controls .initial:n           = false,
  controls .groups:n            = { dynamic },
  muted .bool_set:N             = \l_@@_mediamuted_bool,
  muted .initial:n              = false,
  muted .groups:n               = { dynamic },
  duration .fp_set:N             = \l_@@_mediaduration_fp,
  duration .initial:n            = 0,
  duration .value_required:n     = true,
  duration .groups:n             = { animation },
  pdfprogress .code:n            = { \msg_fatal:nnnn { beamerreveal / Syntax } { key-syntax-changed }
    { pdfprogress=#1 } { pdf~progress=#1 } },
  pdfprogress .groups:n          = { animation },
  pdf~progress .fp_set:N         = \l_@@_mediapdfprogress_fp,
  pdf~progress .initial:n        = 0,
  pdf~progress .value_required:n = true,
  pdf~progress .groups:n         = { animation },
  handout~progress .tl_set:N     = \l_@@_mediahandoutprogress_tl,
  handout~progress .value_required:n = true,
  handout~progress .groups:n     = { animation },
  framerate .fp_set:N            = \l_@@_mediaframerate_fp,
  framerate .initial:n           = 0,
  framerate .value_required:n    = true,
  framerate .groups:n            = { animation },
  expand~once .bool_set:N         = \l_@@_mediaexpandonce_bool,
  expand~once .initial:n          = false,
  expand~once .groups:n           = { animation },
  anchor .choice:,
  anchor / center .code:n       = { \fp_set:Nn \l_@@_xposdelta_fp { -0.5 }
                                    \fp_set:Nn \l_@@_yposdelta_fp { -0.5 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / west .code:n         = { \fp_set:Nn \l_@@_xposdelta_fp { 0 }
                                    \fp_set:Nn \l_@@_yposdelta_fp { -0.5 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / north~west .code:n   = { \fp_set:Nn \l_@@_xposdelta_fp { 0 }
                                    \fp_set:Nn \l_@@_yposdelta_fp { 0 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / north .code:n        = { \fp_set:Nn \l_@@_xposdelta_fp { -0.5 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { 0 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / north~east .code:n   = { \fp_set:Nn \l_@@_xposdelta_fp { -1 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { 0 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / east .code:n         = { \fp_set:Nn \l_@@_xposdelta_fp { -1 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { -0.5 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / south~east .code:n   = { \fp_set:Nn \l_@@_xposdelta_fp { -1 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { -1 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / south .code:n        = { \fp_set:Nn \l_@@_xposdelta_fp { -0.5 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { -1 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor / south~west .code:n   = { \fp_set:Nn \l_@@_xposdelta_fp { 0 } 
                                    \fp_set:Nn \l_@@_yposdelta_fp { -1 }
                                    \tl_set:Nn \l_@@_mediaanchor_tl {#1} },
  anchor .value_required:n      = true,
  anchor .initial:n             = center,
  anchor .groups:n              = { position },
  above .meta:n                 = { anchor = south },
  above .groups:n               = { position },
  below .code:n                 = { anchor = north },
  below .groups:n               = { position },
  left .code:n                  = { anchor = east },
  left .groups:n                = { position },
  right .code:n                 = { anchor = west },
  right .groups:n               = { position },
  above~left .code:n            = { anchor = south east },
  above~left .groups:n          = { position },
  above~right .code:n           = { anchor = south west },
  above~right .groups:n         = { position },
  below~left .code:n            = { anchor = north east },
  below~left .groups:n          = { position },
  below~right .code:n           = { anchor = north west },
  below~right .groups:n         = { position },
  unknown .code:n =
  {
    \msg_fatal:nne { beamerreveal / Syntax } { unknown-key } {\l_keys_key_str}
  },
}
%</reveal>
%    \end{macrocode}
%
% \subsection{Fiddling with relative widths/heights}
% As mentioned in the section 'quirks' the package only allows specifying
% box dimensions as height and an apsect ratio, or width and an
% aspectratio. \textsc{beamer-reveal} will recalculate these into
% fractional values relative to the slide width and height.\\
% In order not to get lost in the calculations, let's find the equations we need to implement.
% Let's call the absolute width and height $W$ and $L$ and the relative width and height $w$ and $h$.
% Let $W_P$ and $H_P$ be the absolute page width and height. Obviously:
% \begin{align}
%   w &= \frac{W}{W_P} & h = \frac{H}{H_P}
% \end{align}
% Now let's denote the aspectratio of an object as $A$ and the aspectratio of the page as $A_P$.
% \begin{align}
%   A &= \frac{W}{H} & A_P &=\frac{W_P}{H_P}
% \end{align}
% This allows to calculate $w$ from $h$ and vice versa:
% \begin{align}
%   w &= \frac{W}{W_P} = \frac{AH}{A_P H_P} = \frac{A}{A_P} h &
%   h &= \frac{H}{H_P} = \frac{W/A}{W_P/A_P} = \frac{A_P}{A} w
% \end{align}
% The following macro calculates verifies if at least the aspectratio $A$ has been given otherwise
% a fatal error is generated. It then calculates $w$ from $h$ or $h$ from $w$ unless both $w$ and $h$
% are missing, or unless both have been specified.
% \begin{macro}{\process\_a\_w\_h\_@@:NNN}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \process_a_w_h_@@:NNN #1#2#3 {
  \fp_compare:nNnTF { #1 } = {0} {
    \msg_fatal:nn { beamer-reveal } { missing-aspectratio }
  } {
    \fp_compare:nNnTF { #2 } = {0} {
      \fp_compare:nNnTF { #3 } = {0} {
        \msg_fatal:nn { beamer-reveal } { missing-width-or-height }
      } {
        % calculating w
        \fp_gset:Nn \l_tmpa_fp { round( #1 / \g_@@_canvasaspectratio_fp * #3, 6 ) }
        \fp_gset:Nn \l_tmpb_fp { #3 }
      }
    } {
      \fp_compare:nNnTF { #3 } = {0} {
        % calculating h
        \fp_gset:Nn \l_tmpa_fp { #2 }
        \fp_gset:Nn \l_tmpb_fp { round( \g_@@_canvasaspectratio_fp / #1 * #2, 6 ) }
      } {
        \msg_fatal:nn { beamer-reveal } { overconstrained-box }
      }
    }
  }
  \fp_set_eq:NN #2 \l_tmpa_fp
  \fp_set_eq:NN #3 \l_tmpb_fp
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Auxiliary functions}
%
% \begin{macro}{\@@extractloleft}
%    \begin{macrocode}
%<*reveal>
\newdimen\xloleft
\newdimen\yloleft
\newcommand*\@@extractloleft[1]{\path  (#1);\pgfgetlastxy{\xloleft}{\yloleft};}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@extractupright}
%    \begin{macrocode}
%<*reveal>
\newdimen\xupright
\newdimen\yupright
\newcommand*\@@extractupright[1]{\path (#1);\pgfgetlastxy{\xupright}{\yupright};}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% Finally, some native l3exp fp variables to hold $x$ and $y$ position.
%
%    \begin{macrocode}
%<*reveal>
\fp_new:N \l_@@_xpos_fp
\fp_new:N \l_@@_ypos_fp
%</reveal>
%    \end{macrocode}
%
% \subsection{Macros}
% \subsubsection{Main macros}
% The macro's fiddle with positions and sizes of boxes. Therefore it helps to have the following
% pictures in mind when reading the code.
%
% The parameters |\posx| and |\posy| are the relative \textsc{beamer} coördinates of the box.
% The parameters |\l_@@_xpos_fp| and |\l_@@_ypos_fp| are the HTML top and left distances
% of the top left corner of the box. All parameters are relative to the screen canvas dimensions
% (and therefore have values in between 0 and 1).
%
% \begin{center}
%   \begin{tikzpicture}[scale=0.4,font=\footnotesize,
%                       inner sep=1pt]
%     \draw[thick] (0,0) node[below right] {Screen canvas} rectangle (18,10);
%     \coordinate (m) at (12,5);
%     \coordinate (c) at ($(m)+(-3,2)$);
%     \draw[semithick] ($(m)-(3,2)$) node[below right] {Box} rectangle ($(m)+(3,2)$);
%     \fill (m) circle[radius=2pt];
%     \draw[<->] (m|-0,0) -- node[right,pos=0.33] {|\textbackslash{}posy|} (m);
%     \draw[<->] (m-|0,0) -- node[below,pos=0.4] {|\textbackslash{}posx|} (m);
%     \draw[<->] (c|-0,10) -- node[right,pos=0.5] {|\textbackslash{}l\_@@\_ypos\_fp|} (c);
%     \draw[<->] (c-|0,10) -- node[below,pos=0.5] {|\textbackslash{}l\_@@\_xpos\_fp|} (c);
%   \end{tikzpicture}
% \end{center}
% The width and height of the box have dedicated parameters.
% \begin{center}
%   \begin{tikzpicture}[scale=0.4,font=\footnotesize,
%                       inner sep=1pt],
%     \draw[thick] (0,0) node[below right] {Screen canvas} rectangle (18,10);
%     \coordinate (m) at (12,5);
%     \coordinate (c) at ($(m)+(-3,2)$);
%     \draw[semithick] ($(m)-(3,2)$) node[below right] {Box} rectangle ($(m)+(3,2)$);
%     \fill (m) circle[radius=2pt];
%     \draw[ultra thin]
%       (9,7) -- (9,8.1)
%       (15,7) -- (15,8.1);
%     \draw[<->] (9,8) -- node[above] {|\textbackslash{}l\_@@\_mediawidth\_fp|}  (15,8);
%     \draw[ultra thin]
%       (9,3) -- (7.9,3)
%       (9,7) -- (7.9,7);
%     \draw[<->] (8,3) -- node[left] {|\textbackslash{}l\_@@\_mediaheight\_fp|}  (8,7);
%   \end{tikzpicture}
% \end{center}
% The anchor of a box can be any of the main 8 wind directions (north, east, south, west, and the ones in between those).
% This anchor location in combination with the width and height of the box, allow for a correction on the HTML coordinates.
% The correction coefficients (relative to width and height) are:
%
% \begin{center}
%   \begin{tikzpicture}[scale=0.4,font=\footnotesize,
%                       inner sep=1pt]
%     \draw[thick] (0,0) node[below right] {Screen canvas} rectangle (18,10);
%     \coordinate (m) at (12,5);
%     \coordinate (c) at ($(m)+(-3,2)$);
%     \draw[semithick,gray] ($(m)-(3,2)$) rectangle ($(m)+(3,2)$);
%     \foreach \x/\xpos in {0/left,0.5/,1/right} {
%        \foreach \y/\ypos in {0/above,0.5/above,1/below} {
%           \coordinate (p) at ($(c)+({\x*6},{-\y*4})$);
%           \node[font=\tiny,\ypos] at (p) {$({-\x},{-\y})$};
%           \fill (p) circle[radius=2pt];
%        }
%     }
%     \fill (m) circle[radius=2pt];
%   \end{tikzpicture}
% \end{center}
%
% The flow of the macros is as follows. We use the |\video| macro as example:\\[-2\baselineskip]
% \begin{verbatim}
% - |\video|:
%   - knows it is a |Dynamic| element (= XXX below)
%   - parses the appropriate keys from the option parameter list
%   - raises a fatal error if unknown keys have been detected
%   - hands over to the
%     |\contentDispatcher|:
%     - checks if this is overlay content (|\at (x,y)|); hands over to the
%       |\overlayXXXContent|: generates overlay content
%     - checks if this is insert content (no |\at (x,y)|); hands over to the
%       |\insertXXXContent|: generates insert content
%     - otherwise: raises correct fatal syntax errors
% \end{verbatim}
%
% \begin{macro}{\video}
%    \begin{macrocode}
%<*reveal>
\tl_new:N \l_@@_keyoverflow_tl
\NewDocumentCommand\video{D<>{1-} O{} d() t\at d() m }{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { animation } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-video } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {video}
                                  \overlayDynamicContent_@@:nnnn
                                  \insertDynamicContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\audio}
%    \begin{macrocode}
%<*reveal>
\NewDocumentCommand\audio{ D<>{1-} O{} d() t\at d() m }{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { animation } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-audio } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {audio}
                                  \overlayDynamicContent_@@:nnnn
                                  \insertDynamicContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\iframe}
%    \begin{macrocode}
%<*reveal>
\NewDocumentCommand\iframe{D<>{1-} O{} d() t\at d() m }{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { dynamic animation } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-iframe } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {iframe}
                                  \overlayDynamicContent_@@:nnnn
                                  \insertDynamicContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% %\end{macro}
%
% \begin{macro}{\image}
%    \begin{macrocode}
%<*reveal>
\NewDocumentCommand\image{D<>{1-} O{} d() t\at d() m}{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { dynamic } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-image } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {image}
                                  \overlayStaticContent_@@:nnnn
                                  \insertStaticContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% %\end{macro}
%
% \begin{macro}{\animation}
%    \begin{macrocode}
%<*reveal>
\NewDocumentCommand\animation{D<>{1-} O{} d() t\at d() +m}{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { size, fit } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-animation } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {animation}
                                  \overlayFixedContent_@@:nnnn
                                  \insertFixedContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\still}
%    \begin{macrocode}
%<*reveal>
\NewDocumentCommand\still{D<>{1-} O{} d() t\at d() +m}{
  \only<#1> {
    % begin group to keep the key setting local
    \group_begin:
    \keys_set_exclude_groups:nnnN { beamerreveal / media } { size, fit } { #2 } \l_@@_keyoverflow_tl
    \tl_if_empty:NTF \l_@@_keyoverflow_tl {} {
      \msg_fatal:nne { beamerreveal / Syntax } { illegal-keys-animation } { \l_@@_keyoverflow_tl }
    }
    \contentDispatcher_@@:nnnnnNN {#3} {#4} {#5} {#6} {still}
                                  \overlayFixedContent_@@:nnnn
                                  \insertFixedContent_@@:nnn
    \group_end:
  }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{Auxiliary macros}
%
% \begin{macro}{\at}\\
% This is actually no macro, it even won't clash with a macro called |\at| that the
% user may declare. It is just a parsing token as documented in |usrguide.pdf|
% under 'control sequence tokens'.
% \end{macro}
%
% \begin{macro}{\contentDispatcher\_@@:nnnnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \contentDispatcher_@@:nnnnnNN #1 #2 #3 #4 #5 #6 #7 {
  \IfBooleanTF{#2}
              {% \at
                \IfNoValueTF{#3}
                            { \msg_fatal:nn { beamerreveal / Syntax } { missing-coordinate } }
                            { #6 {#1} {#3} {#4} {#5} }
              }
              {
                %no \at
                \IfNoValueTF{#3}
                            {
                              \tl_if_eq:nnTF {#4} a
                                 { \msg_fatal:nn { beamerreveal / Syntax } { old-at-syntax } }
                                 { #7 {#1} {#4} {#5} }
                            }
                            { \msg_fatal:nn { beamerreveal / Syntax } { missing-at } }
              }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\overlayDynamicContent\_@@:nnnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \overlayDynamicContent_@@:nnnn #1#2#3#4 {
  % convert combination width/aspectratio to height, or
  %                     height/aspectratio to width
  \process_a_w_h_@@:NNN \l_@@_mediaaspectratio_fp \l_@@_mediawidth_fp \l_@@_mediaheight_fp
  
    % extract relative position from bottom left of page (0,0) to top right (1,1)
  \seq_set_split:Nnn \l_tmpa_seq { , } { #2 }
  \pgfmathsetmacro{\posx}{\seq_item:Nn \l_tmpa_seq {1}}
  \pgfmathsetmacro{\posy}{\seq_item:Nn \l_tmpa_seq {2}}
  % convert to html coordinates from top left corner, and correct for anchor location
  \fp_set:Nn \l_@@_xpos_fp { \posx + \l_@@_xposdelta_fp * \l_@@_mediawidth_fp }
  \fp_set:Nn \l_@@_ypos_fp { (1-\posy) + \l_@@_yposdelta_fp * \l_@@_mediaheight_fp }

  % write info to .rvl file
  \writeliteral_@@:n {
    -#4:
      width={\fp_use:N \l_@@_mediawidth_fp},
      height={\fp_use:N \l_@@_mediaheight_fp},
      fit={\tl_use:N \l_@@_mediafit_tl},
      background={\tl_use:N \l_@@_mediabackground_tl},
      \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={},} {}
      \bool_if:NTF \l_@@_mediacontrols_bool {controls={},} {}
      \bool_if:NTF \l_@@_medialoop_bool {loop={},} {}
      \bool_if:NTF \l_@@_mediamuted_bool {muted={},} {}
      \bool_if:NTF \l_@@_mediaembed_bool {embed={},} {}
      x={\fp_use:N \l_@@_xpos_fp},
      y={\fp_use:N \l_@@_ypos_fp},
      file={#3}
  }
  
  % write node to PDF file
  \bool_if:NTF \l_@@_mediaboxdraw_bool {
    \begin{tikzpicture}[overlay,remember~picture,font=\tiny]
      \@@extractloleft{$(current~page.south~west)$}
      \@@extractupright{$(current~page.north~east)$}
      \node[
        anchor = \tl_use:N \l_@@_mediaanchor_tl,
        minimum~width={\fp_use:N \l_@@_mediawidth_fp * (\xupright - \xloleft)},
        minimum~height={\fp_use:N \l_@@_mediaheight_fp * (\yupright - \yloleft)},
        draw,
        fill=\tl_use:N \l_@@_mediabackground_tl,
      ] (#1) at ({\xloleft*(1-\posx)+\xupright*\posx},{\yloleft*(1-\posy)+\yupright*\posy})
           {\textcolor{gray}{#3}};
    \end{tikzpicture}
  }{}
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\insertDynamicContent\_@@:nnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \insertDynamicContent_@@:nnn #1#2#3 {
  % parameters: nodename filename content-type
  % convert combination width/aspectratio to height, or
  %                     height/aspectratio to width
  \process_a_w_h_@@:NNN \l_@@_mediaaspectratio_fp \l_@@_mediawidth_fp \l_@@_mediaheight_fp
  
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \pagewidth } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pageheight } }

  % write node to PDF file
  \begin{tikzpicture}[remember~picture,font=\tiny]
    \node[
      outer~sep=0pt,inner~sep=0pt,rectangle,
      anchor = \tl_use:N \l_@@_mediaanchor_tl,
      minimum~width={\fp_use:N \l_@@_mediawidth_fp * \fp_use:N \l_tmpa_fp },
      minimum~height={\fp_use:N \l_@@_mediaheight_fp * \fp_use:N \l_tmpb_fp },
      \bool_if:NTF \l_@@_mediaboxdraw_bool {draw}{},
      fill=\tl_use:N \l_@@_mediabackground_tl,
    ] (#1) {\bool_if:NTF \l_@@_mediaboxdraw_bool {\textcolor{gray}{#2}}{}};
    \path let \p1=($(#1.north~west) - (current~page.north~west)$)
    in \pgfextra{
      \fp_set:Nn \l_@@_xpos_fp { \x1 / \fp_use:N \l_tmpa_fp }
      \fp_set:Nn \l_@@_ypos_fp { - \y1 / \fp_use:N \l_tmpb_fp }
      % write info to .rvl file
      \writeliteral_@@:n {
        -#3:
        width={\fp_use:N \l_@@_mediawidth_fp},
        height={\fp_use:N \l_@@_mediaheight_fp},
        fit={\tl_use:N \l_@@_mediafit_tl},
        background={\tl_use:N \l_@@_mediabackground_tl},
        \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={},} {}
        \bool_if:NTF \l_@@_mediacontrols_bool {controls={},} {}
        \bool_if:NTF \l_@@_medialoop_bool {loop={},} {}
        \bool_if:NTF \l_@@_mediamuted_bool {muted={},} {}
        x={\fp_use:N \l_@@_xpos_fp},
        y={\fp_use:N \l_@@_ypos_fp},
        file={#2}
      }
    };
  \end{tikzpicture}
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\overlayStaticContent\_@@:nnnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \overlayStaticContent_@@:nnnn #1#2#3#4 {
  % convert combination width/aspectratio to height, or
  %                     height/aspectratio to width
  \process_a_w_h_@@:NNN \l_@@_mediaaspectratio_fp \l_@@_mediawidth_fp \l_@@_mediaheight_fp
  
  % extract relative position from bottom left of page (0,0) to top right (1,1)
  \seq_set_split:Nnn \l_tmpa_seq { , } { #2 }
  \pgfmathsetmacro{\posx}{\seq_item:Nn \l_tmpa_seq {1}}
  \pgfmathsetmacro{\posy}{\seq_item:Nn \l_tmpa_seq {2}}
  % convert to html coordinates from top left corner, and correct for anchor location
  \fp_set:Nn \l_@@_xpos_fp { \posx + \l_@@_xposdelta_fp * \l_@@_mediawidth_fp }
  \fp_set:Nn \l_@@_ypos_fp { (1-\posy) + \l_@@_yposdelta_fp * \l_@@_mediaheight_fp }
  
  % write info to .rvl file
  \writeliteral_@@:n {
    -#4:
    width={\fp_use:N \l_@@_mediawidth_fp},
    height={\fp_use:N \l_@@_mediaheight_fp},
    fit={\tl_use:N \l_@@_mediafit_tl},
    background={\tl_use:N \l_@@_mediabackground_tl},
    \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={true},} {}
    \bool_if:NTF \l_@@_mediaembed_bool {embed={},} {}
    x={\fp_use:N \l_@@_xpos_fp},
    y={\fp_use:N \l_@@_ypos_fp},
    file={#3}
  }

  % write node to PDF file
  \bool_if:NTF \l_@@_mediaboxdraw_bool {
    \begin{tikzpicture}[overlay,remember~picture,font=\tiny]
      \@@extractloleft{$(current~page.south~west)$}
      \@@extractupright{$(current~page.north~east)$}
      \node[
        anchor = \tl_use:N \l_@@_mediaanchor_tl,
        minimum~width={\fp_use:N \l_@@_mediawidth_fp * (\xupright - \xloleft)},
        minimum~height={\fp_use:N \l_@@_mediaheight_fp * (\yupright - \yloleft)},
        draw,
        fill=\tl_use:N \l_@@_mediabackground_tl,
      ] (#1) at ({\xloleft*(1-\posx)+\xupright*\posx},{\yloleft*(1-\posy)+\yupright*\posy})
           {\textcolor{gray}{#3}};
    \end{tikzpicture}
  }{}
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\insertStaticContent\_@@:nnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \insertStaticContent_@@:nnn #1#2#3 {
  % convert combination width/aspectratio to height, or
  %                     height/aspectratio to width
  \process_a_w_h_@@:NNN \l_@@_mediaaspectratio_fp \l_@@_mediawidth_fp \l_@@_mediaheight_fp

  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \pagewidth } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pageheight } }

  % write node to PDF file
  \begin{tikzpicture}[remember~picture,font=\tiny]%
    \node[
      outer~sep=0pt,inner~sep=0pt,rectangle,
      anchor = \tl_use:N \l_@@_mediaanchor_tl,
      minimum~width={\fp_use:N \l_@@_mediawidth_fp * \fp_use:N \l_tmpa_fp },
      minimum~height={\fp_use:N \l_@@_mediaheight_fp * \fp_use:N \l_tmpb_fp },
      \bool_if:NTF \l_@@_mediaboxdraw_bool {draw}{},
      \bool_if:NTF \l_@@_mediaembed_bool {embed={},} {}
      fill=\tl_use:N \l_@@_mediabackground_tl,
    ] (#1) {\bool_if:NTF \l_@@_mediaboxdraw_bool {\textcolor{gray}{#2}}{}};
    \path let \p1=($(#1.north~west) - (current~page.north~west)$)
    in \pgfextra{
      \fp_set:Nn \l_@@_xpos_fp { \x1 / \fp_use:N \l_tmpa_fp }
      \fp_set:Nn \l_@@_ypos_fp { - \y1 / \fp_use:N \l_tmpb_fp }
      % write info to .rvl file
      \writeliteral_@@:n {
        -#3:
        width={\fp_use:N \l_@@_mediawidth_fp},
        height={\fp_use:N \l_@@_mediaheight_fp},
        fit={\tl_use:N \l_@@_mediafit_tl},
        background={\tl_use:N \l_@@_mediabackground_tl},
        \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={true},} {}
        x={\fp_use:N \l_@@_xpos_fp},
        y={\fp_use:N \l_@@_ypos_fp},
        file={#2}
      }
    };
  \end{tikzpicture}
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\overlayFixedContent\_@@:nnnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \overlayFixedContent_@@:nnnn #1#2#3#4 {
  % first create the box with the content and measure it
  \pgfmathsetmacro\progress{ \fp_use:N \l_@@_mediapdfprogress_fp }%
  \hbox_set:Nn \l_tmpa_box {\tl_trim_spaces:n{#3}}
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \box_wd:N \l_tmpa_box } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pagewidth } }
  \fp_set:Nn \l_@@_mediawidth_fp { \fp_eval:n { \l_tmpa_fp / \l_tmpb_fp } }
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \box_ht:N \l_tmpa_box } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pageheight } }
  \fp_set:Nn \l_@@_mediaheight_fp { \fp_eval:n { \l_tmpa_fp / \l_tmpb_fp } }
  
  % extract relative position from bottom left of page (0,0) to top right (1,1)
  \seq_set_split:Nnn \l_tmpa_seq { , } { #2 }
  \pgfmathsetmacro{\posx}{\seq_item:Nn \l_tmpa_seq {1}}
  \pgfmathsetmacro{\posy}{\seq_item:Nn \l_tmpa_seq {2}}
  
  % convert to html coordinates from top left corner, and correct for anchor location
  \fp_set:Nn \l_@@_xpos_fp { \posx + \l_@@_xposdelta_fp * \l_@@_mediawidth_fp }
  \fp_set:Nn \l_@@_ypos_fp { (1-\posy) + \l_@@_yposdelta_fp * \l_@@_mediaheight_fp }

  % write .rvl information
  \writeliteral_@@:n {
    -#4:
    width={ \fp_use:N \l_@@_mediawidth_fp },
    height={ \fp_use:N \l_@@_mediaheight_fp },
    framerate={ \fp_use:N \l_@@_mediaframerate_fp },
    duration={ \fp_use:N \l_@@_mediaduration_fp },
    progress={ \fp_use:N \l_@@_mediapdfprogress_fp },
    \bool_if:NTF \l_@@_mediaembed_bool {embed={},} {}
    x={\fp_use:N \l_@@_xpos_fp},
    y={\fp_use:N \l_@@_ypos_fp},
    fit={fit},
    background={\tl_use:N \l_@@_mediabackground_tl},
    \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={},} {}
    \bool_if:NTF \l_@@_medialoop_bool {loop={},} {}
    \bool_if:NTF \l_@@_mediacontrols_bool {controls={},} {}
  }

  % put node in PDF files
  \begin{tikzpicture}[overlay,remember~picture,font=\tiny]%
    \@@extractloleft{$(current~page.south~west)$}
    \@@extractupright{$(current~page.north~east)$}
    \node[
      outer~sep=0pt,inner~sep=0pt,rectangle,
      \bool_if:NTF \l_@@_mediaboxdraw_bool {draw}{},
    ]
    (#1) at ({\xloleft*(1-\posx)+\xupright*\posx},{\yloleft*(1-\posy)+\yupright*\posy})
          {\box_use:N \l_tmpa_box};
  \end{tikzpicture}%


  %
  % write code to .rvl file
  \bool_if:NTF \l_@@_mediaexpandonce_bool
       { \writeraw_@@:o { #3 } } { \writeraw_@@:n { #3 } }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\insertFixedContent\_@@:nnn}
%    \begin{macrocode}
%<*reveal>
\cs_new:Npn \insertFixedContent_@@:nnn #1#2#3 {
  %% % first create the box with the content and measure it
  % check if we are in handout mode
  \str_if_eq:eeTF { \use:c { beamer@currentmode } } { handout }
      {
        \regex_split:nVN { , } { \l_@@_mediahandoutprogress_tl } \l_tmpa_seq
        % \seq_show:N \l_tmpa_seq
        \seq_map_inline:Nn  \l_tmpa_seq {
          \regex_split:nnN { : } { ##1 } \l_tmpb_seq
          \int_compare:nT { \use:c {beamer@overlaynumber} == \seq_item:Nn \l_tmpb_seq {1} }
              {
                \pgfmathsetmacro\progress{ \seq_item:Nn \l_tmpb_seq {2} }
              }

        }
      }
      { \pgfmathsetmacro \progress { \fp_use:N \l_@@_mediapdfprogress_fp } }
      
  \hbox_set:Nn \l_tmpa_box {\tl_trim_spaces:n{#2}}
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \box_wd:N \l_tmpa_box } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pagewidth } }
  \fp_set:Nn \l_@@_mediawidth_fp { \fp_eval:n { \l_tmpa_fp / \l_tmpb_fp } }
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \box_ht:N \l_tmpa_box } }
  \fp_set:Nn \l_tmpb_fp { \dim_eval:n { \pageheight } }
  \fp_set:Nn \l_@@_mediaheight_fp { \fp_eval:n { \l_tmpa_fp / \l_tmpb_fp } }
  % restore the pagewidth in tmpa
  \fp_set:Nn \l_tmpa_fp { \dim_eval:n { \pagewidth } }
  
  % write node to PDF file
  \begin{tikzpicture}[remember~picture,font=\tiny]
    \node[
      outer~sep=0pt,inner~sep=0pt,rectangle,
      \bool_if:NTF \l_@@_mediaboxdraw_bool {draw}{},
    ] (#1) {\box_use:N \l_tmpa_box};
    \path let \p1=($(#1.north~west) - (current~page.north~west)$)
    in \pgfextra{
      \fp_set:Nn \l_@@_xpos_fp { \x1 / \fp_use:N \l_tmpa_fp }
      \fp_set:Nn \l_@@_ypos_fp { - \y1 / \fp_use:N \l_tmpb_fp }
      % write info to .rvl file
      \writeliteral_@@:n {
        -#3:
        width={ \fp_use:N \l_@@_mediawidth_fp },
        height={ \fp_use:N \l_@@_mediaheight_fp },
        framerate={ \fp_use:N \l_@@_mediaframerate_fp },
        duration={ \fp_use:N \l_@@_mediaduration_fp },
        progress={ \fp_use:N \l_@@_mediapdfprogress_fp },
        \bool_if:NTF \l_@@_mediaembed_bool {embed={},} {}
        x={\fp_use:N \l_@@_xpos_fp},
        y={\fp_use:N \l_@@_ypos_fp},
        fit={fit},
        background={\tl_use:N \l_@@_mediabackground_tl},
        \bool_if:NTF \l_@@_mediaautoplay_bool {autoplay={},} {}
        \bool_if:NTF \l_@@_medialoop_bool {loop={},} {}
        \bool_if:NTF \l_@@_mediacontrols_bool {controls={},} {}
      }
    };
  \end{tikzpicture}
  \bool_if:NTF \l_@@_mediaexpandonce_bool
       { \writeraw_@@:o { #2 } } { \writeraw_@@:n { #2 } }
}
%</reveal>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Postamble}
%
%    \begin{macrocode}
%<*reveal>
\AtEndDocument{
  \ExplSyntaxOn
  \iow_close:N \g_@@_rvlfile
  \ExplSyntaxOff
}
\ExplSyntaxOff
%</reveal>
%    \end{macrocode}
% \clearpage
%
% \bibliographystyle{alpha}
%
% \begin{thebibliography}{99}
%
% \bibitem{beamer}
% Till Tantau et al., "beamer - A \LaTeX{} class for producing
% presentations and slides",
% \newblock \url{https://ctan.org/pkg/beamer},
% \newblock online, accessed in December 2025.
% \bibitem{movie15}
% Alexander Grahn, "movie15 - Multimedia inclusion package",
% \newblock \url{https://ctan.org/pkg/movie15},
% \newblock online, accessed in December 2025.
% \bibitem{media9}
% Alexander Grahn, "media9 - Multimedia inclusion package with Adobe Reader-9/X compatibility",
% \newblock \url{https://ctan.org/pkg/media9},
% \newblock online, accessed in December 2025.
% \bibitem{reveal}
% Hakim El Hattab and contributors, "reveal.js - The HTML Presentation framework",
% \newblock \url{https://revealjs.com},
% \newblock online, accessed in January 2026.
% \bibitem{quarto}
% Posit Software - PBC, "Quarto - An open-source scientific and technical publishing system",
% \newblock \url{https://quarto.org},
% \newblock online, accessed in January 2026.
% \bibitem{manim}
% Grant Sanderson, "manim - A community maintained Python library for creating mathematical animations",
% \newblock \url{https://www.manim.community},
% \newblock online, accessed in December 2025.
% \bibitem{pdfcrop}
% Heiko Oberdiek, "pdfcrop - Crop PDF graphics",
% \newblock \url{https://ctan.org/pkg/pdfcrop},
% \newblock online, accessed in December 2025.
% \bibitem{pdftoppm}
% Poppler developers, "Poppler Utilities (pdftoppm)",
% \newblock \url{https://poppler.freedesktop.org},
% \newblock oline, accessed in December 2025.
% \bibitem{ffmpeg}
% FFmpeg developers, "ffmpeg tool",
% \newblock \url{https://ffmpeg.org},
% \newblock oline, accessed in December 2025.
% \end{thebibliography}
%
% \Finale
\endinput
