texlive[49204] Master/texmf-dist: animate (20nov18)

commits+karl at tug.org commits+karl at tug.org
Tue Nov 20 23:01:10 CET 2018


Revision: 49204
          http://tug.org/svn/texlive?view=revision&revision=49204
Author:   karl
Date:     2018-11-20 23:01:10 +0100 (Tue, 20 Nov 2018)
Log Message:
-----------
animate (20nov18)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/animate/ChangeLog
    trunk/Master/texmf-dist/doc/latex/animate/README
    trunk/Master/texmf-dist/doc/latex/animate/animate.pdf
    trunk/Master/texmf-dist/source/latex/animate/animate.tex
    trunk/Master/texmf-dist/tex/latex/animate/animate.sty

Modified: trunk/Master/texmf-dist/doc/latex/animate/ChangeLog
===================================================================
--- trunk/Master/texmf-dist/doc/latex/animate/ChangeLog	2018-11-20 22:00:50 UTC (rev 49203)
+++ trunk/Master/texmf-dist/doc/latex/animate/ChangeLog	2018-11-20 22:01:10 UTC (rev 49204)
@@ -1,3 +1,10 @@
+2018-11-20
+	* fix : `autoplay' (non-functional in SVG output); documentation
+	updated (additions in section on SVG)
+
+2018-11-19
+	* new : support for `dvisvgm' output driver
+
 2018-08-22
 	* new : `export' package option
 

Modified: trunk/Master/texmf-dist/doc/latex/animate/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/animate/README	2018-11-20 22:00:50 UTC (rev 49203)
+++ trunk/Master/texmf-dist/doc/latex/animate/README	2018-11-20 22:01:10 UTC (rev 49204)
@@ -11,25 +11,29 @@
 ==============
 
 This package provides an interface to create portable, JavaScript driven PDF
-animations from sets of (vector) graphics or rasterized image files or from
-inline (vector) graphics, such as LaTeX-picture, PSTricks or pgf/TikZ
+and SVG animations from sets of (vector) graphics or rasterized image files
+or from inline (vector) graphics, such as LaTeX-picture, PSTricks or pgf/TikZ
 generated pictures, or just from typeset text.
 
 It supports the usual PDF making workflows, i. e.  pdfLaTeX, LaTeX -> dvips
--> ps2pdf (Ghostscript)/Distiller and (Xe)LaTeX -> (x)dvipdfmx, LuaLaTeX.
+-> ps2pdf (Ghostscript)/Distiller, (Xe)LaTeX -> (x)dvipdfmx, LuaLaTeX, and
+LaTeX -> dvisvgm for SVG.
 
-The resulting PDF with animations can be viewed in Acrobat Reader (except on
-mobile devices), in PDF-XChange and in Foxit Reader.
+The resulting PDF with animations can be viewed in Acrobat Reader (except
+on mobile devices), in PDF-XChange and in Foxit Reader. Animated SVG are
+self-contained files that can be embedded into HTML using the `<object>` tag or
+opened directly in a Web browser, such as Firefox or Chromium.
 
 Note, this file only gives a summary of usage and available package and
 command options. Please refer to the documentation `animate.pdf' for details
 and examples.
 
- * Keywords: include portable PDF animated PDF animation animating
-             embed animated graphics LaTeX pdfLaTeX PSTricks pgf TikZ MetaPost
-             LaTeX-picture inline graphics vector graphics animated GIF LaTeX
-             dvips ps2pdf dvipdfmx XeLaTeX JavaScript Acrobat Reader PDF-XChange
-             Foxit Reader
+ * Keywords: include portable PDF animation SVG animation animated PDF animated
+             SVG dvisvgm html TeX4ht web animating embed animated graphics
+             LaTeX pdfLaTeX LuaLaTeX PSTricks pgf TikZ LaTeX-picture MetaPost
+             inline graphics vector graphics animated GIF LaTeX dvips ps2pdf
+             dvipdfmx XeLaTeX JavaScript Acrobat Reader PDF-XChange Foxit Reader
+             Firefox Chrome Chromium
 
 
 2. Usage
@@ -45,7 +49,8 @@
                     buttonbg=<colour>, buttonfg=<colour>, buttonalpha=<opacity>,
                     loop, palindrome, step,
                     poster[=first | <num> | last | none],
-                    method=icon | widget | ocg, dvipdfmx, xetex,
+                    method=icon | widget | ocg,
+                    dvipdfmx, dvisvgm, xetex,
                     type=[<file ext>],
                     export
 
@@ -88,7 +93,9 @@
  * pdfTeX, version >= 1.20, or LuaLaTeX, version >= 0.95
  * Ghostscript, version >= 9.15 or Adobe Distiller
  * dvipdfmx, version >= 20080607
+ * dvisvgm
  * Acrobat Reader (version >= 7), PDF-XChange, Foxit Reader
+ * Firefox, Chrome, Chromium
 
 
 4. Installation

Modified: trunk/Master/texmf-dist/doc/latex/animate/animate.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/animate/animate.tex
===================================================================
--- trunk/Master/texmf-dist/source/latex/animate/animate.tex	2018-11-20 22:00:50 UTC (rev 49203)
+++ trunk/Master/texmf-dist/source/latex/animate/animate.tex	2018-11-20 22:01:10 UTC (rev 49204)
@@ -61,7 +61,7 @@
 %  \makeatother
 %\fi
 
-\def\keywords{include portable PDF animation animated PDF animating embed animated graphics LaTeX pdfLaTeX LuaLaTeX PSTricks pgf TikZ LaTeX-picture MetaPost inline graphics vector graphics animated GIF LaTeX dvips ps2pdf dvipdfmx XeLaTeX JavaScript Acrobat Reader PDF-XChange Foxit Reader}
+\def\keywords{include portable PDF animation SVG animation animated PDF animated SVG dvisvgm html TeX4ht web animating embed animated graphics LaTeX pdfLaTeX LuaLaTeX PSTricks pgf TikZ LaTeX-picture MetaPost inline graphics vector graphics animated GIF LaTeX dvips ps2pdf dvipdfmx XeLaTeX JavaScript Acrobat Reader PDF-XChange Foxit Reader Firefox Chrome Chromium}
 \hypersetup{
   pdftitle={The animate Package},
   pdfsubject={Documentation},
@@ -80,7 +80,7 @@
   \def\day{#3}
 }
 
-\hyphenation{Ja-va-Script}
+\hyphenation{Ja-va-Script pro-vid-ed}
 
 \begin{document}
 \title{The {\sffamily animate} Package}
@@ -95,23 +95,23 @@
 \begin{abstract}
 \raggedright
 
-\noindent A LaTeX package for creating portable, JavaScript driven PDF animations from sets of vector graphics or raster image files or from inline graphics.
+\noindent A LaTeX package for creating portable, JavaScript driven PDF and SVG animations from sets of vector graphics or raster image files or from inline graphics.
 \vskip 0.2\baselineskip
 
 \emph{Keywords}: \keywords
 \end{abstract}
-
+%\vspace{1.5cm}
 \tableofcontents
 
 %\newpage
 \section{Introduction}
-This package provides an interface for creating PDFs with animated content from sets of graphics or image files, from inline graphics, such as \LaTeX-picture, PSTricks or pgf/TikZ generated pictures, or just from typeset text. Unlike standard movie/video formats, package `animate' allows for animating vector graphics. The result is roughly similar to the SWF (Flash) format, although not as space-efficient.
+This package provides an interface for creating PDF and SVG files with animated content from sets of graphics or image files, from inline graphics, such as \LaTeX-picture, PSTricks or pgf/TikZ generated pictures, or just from typeset text. Unlike standard movie/video formats, package `animate' allows for animating vector graphics. The result is roughly similar to the SWF (Flash) format, although not as space-efficient.
 
 The user interacts with the animation through optional animation controls or using the mouse like so: Pressing the mouse button over the animation widget immediately pauses a playing animation and releasing it resumes playback. Pressing the shift-key at the same time reverses the playback direction. Keeping the mouse button pressed while moving the mouse pointer off the animation widget permanently pauses playback.
 
-Package `animate' supports the usual PDF making workflows, i.\,e. pdf\LaTeX{}, Lua\LaTeX{}, \LaTeX{} $\rightarrow$ \verb+dvips+ $\rightarrow$ \verb+ps2pdf+/Distiller and \pXepLaTeX{} $\rightarrow$ \verb+(x)dvipdfmx+.
+Package `animate' supports the usual workflows for making PDF, i.\,e. pdf\LaTeX{}, Lua\LaTeX{}, \LaTeX{} $\rightarrow$ \verb+dvips+ $\rightarrow$ \verb+ps2pdf+/Distiller and \pXepLaTeX{} $\rightarrow$ \verb+(x)dvipdfmx+, and \LaTeX{} $\rightarrow$ \verb+dvisvgm+ for SVG.
 
-PDF files with animations can be viewed in Acrobat Reader (except on mobile devices), PDF-XChange and Foxit Reader.
+PDF files with animations can be viewed in Acrobat Reader (except on mobile devices), PDF-XChange and Foxit Reader. Animated SVG produced by means of \LaTeX{} and \verb+dvisvgm+ are self-contained files that can be embedded into HTML using the \verb+<object>+ tag or opened directly in a Web browser, such as Firefox or Chromium.
 
 \section{Requirements}
 \begin{trivlist}
@@ -118,8 +118,10 @@
 %\item $\varepsilon$-\TeX
 \item pdf\TeX{}, version $\ge1.20$, or Lua\TeX{}, version $\ge0.95$, for direct PDF output
 \item Ghostscript, version $\ge9.15$ or Adobe Distiller for PS to PDF conversion
-\item dvipdfmx, version $\ge20080607$ for DVI to PDF conversion
-\item Acrobat Reader (version $\ge7$), PDF-XChange, Foxit Reader
+\item \verb+dvipdfmx+ for DVI to PDF conversion
+\item \verb+dvisvgm+ for DVI to SVG conversion (also requires Ghostscript)
+\item PDF: Acrobat Reader (version $\ge7$), PDF-XChange, Foxit Reader
+\item SVG: Firefox, Chrome/Chromium and others
 \end{trivlist}
 
 \section{Installation}
@@ -140,6 +142,7 @@
 \begin{verbatim}
 dvipdfmx
 xetex
+dvisvgm
 export
 autoplay
 autopause
@@ -164,16 +167,22 @@
 method=icon | widget | ocg
 poster[=first | <num> | last | none]
 \end{verbatim}
-Except for `\verb+dvipdfmx+', `\verb+xetex+' and `\verb+export+', the listed package options are also available (among others) as command options and will be explained shortly. However, if used as package options they have global scope, taking effect on all animations in the document. In turn, command options locally override global settings. Options without an argument are boolean options and can be negated, with the exception of package-only options `\verb+dvipdfmx+', `\verb+xetex+' and `\verb+export+', by appending `\verb+=false+'.
+Except for `\verb+dvipdfmx+', `\verb+xetex+', `\verb+dvisvgm+' and `\verb+export+', the listed package options are also available (among others) as command options and will be explained shortly. However, if used as package options they have global scope, taking effect on all animations in the document. In turn, command options locally override global settings. Options without an argument are boolean options and can be negated, with the exception of package-only options `\verb+dvipdfmx+', `\verb+xetex+', `\verb+dvisvgm+ and `\verb+export+', by appending `\verb+=false+'.
 
 \begin{animateinline}[autoplay,loop,nomouse]{1}\strut\emph{Important:}\newframe[3]\end{animateinline} Option `\verb+-Ppdf+' should \emph{not} be used with \verb+dvips+ when converting DVI to Postscript. If you cannot do without, put `\verb+-D 1200+' \emph{after} `\verb+-Ppdf+' on the command line. Users of \LaTeX-aware text editors with menu-driven toolchain invocation, such as \TeX{}nicCenter, should check the configuration of the \verb+dvips+ call.
 
-All workflows require the `graphicx' package to be loaded explicitly. For \verb+dvipdfmx+, `\verb+dvipdfmx+' must be set as a document class option, as in
+All workflows require the `graphicx' package to be loaded explicitly.
+
+Options `\verb+dvipdfmx+' or `\verb+dvisvgm+' must be set for the document class, as in
 %\verb+\documentclass[dvipdfmx,...]{...}+,
 \begin{verbatim}
   \documentclass[dvipdfmx,...]{...}
 \end{verbatim}
-because this driver cannot be auto-detected by `animate', `graphicx' and other packages.
+or
+\begin{verbatim}
+  \documentclass[dvisvgm,...]{...}
+\end{verbatim}
+because these drivers cannot be auto-detected by `animate', `graphicx' and other packages.
 
 Usually, a second \LaTeX{} run is necessary to resolve internally created object references. A warning message will be issued if appropriate.
 
@@ -229,7 +238,7 @@
   \animategraphics{12}{frame_}{5}{50}
 \end{verbatim}
 
-The possible file formats depend on the output driver being used. In the case of \LaTeX{} + \verb+dvips+, files with the `eps' extension are at first searched for, followed by `mps' (\MP-generated Postscript) and `ps'. With pdf\LaTeX{} and Lua\LaTeX{} the searching order is: (1)~`pdf', (2)~`mps', (3)~`png', (4)~`jpg', (5)~`jpeg', (6)~`jbig2', (7)~`jb2', (8)~`jp2'\footnotemark[1], (9)~`j2k'\footnotemark[1], (10)~`jpx'\footnotemark[1]\footnotetext[1]{Only Lua\LaTeX{} currently supports JPEG2000.} and with \XeLaTeX{} or \LaTeX{}+\verb+dvipdfmx+: (1)~`pdf', (2)~`mps', (3)~`eps', (4)~`ps', (5)~`png', (6)~`jpg', (7)~`jpeg', (8)~`bmp'. That is, files capable of storing vector graphics are found first. Make sure that all file names have \emph{lower case} extensions.
+The possible file formats depend on the output driver being used. In the case of \LaTeX{} + \verb+dvips+, files with the `eps' extension are at first searched for, followed by `mps' (\MP-generated Postscript) and `ps'. With pdf\LaTeX{} and Lua\LaTeX{} the searching order is: (1)~`pdf', (2)~`mps', (3)~`png', (4)~`jpg', (5)~`jpeg', (6)~`jbig2', (7)~`jb2', (8)~`jp2'\footnotemark[1], (9)~`j2k'\footnotemark[1], (10)~`jpx'\footnotemark[1]\footnotetext[1]{Only Lua\LaTeX{} currently supports JPEG2000.}, with \XeLaTeX{} or \LaTeX{}+\verb+dvipdfmx+: (1)~`pdf', (2)~`mps', (3)~`eps', (4)~`ps', (5)~`png', (6)~`jpg', (7)~`jpeg', (8)~`bmp', and with \LaTeX{}+\verb+dvisvgm+: (1)~`eps', (2)~`ps', (3)~`svg', (4)~`png', (5)~`jpg', (6)~`jpeg'. That is, files capable of storing vector graphics are found first. Make sure that all file names have \emph{lower case} extensions.
 
 This searching procedure can be skipped thanks to the package and command option `\verb+type=<file ext>+'. It enforces the embedding of files with the given file name extension \verb+<file ext>+.
 
@@ -250,7 +259,7 @@
 \begin{verbatim}
 label=<label text>
 \end{verbatim}
-The animation is given a label, \verb+<label text>+, which must be unique. Labelling an animation enables its JavaScript programming interface by defining \verb+anim['<label text>']+, which is a JavaScript reference to the animation object. The animation object provides a number of properties and methods that can be used for controlling the animation playback from within user defined JavaScript. For details, see Section~\ref{sect:api}.
+The animation is given a label, \verb+<label text>+, which must be unique. Labelling an animation enables its JavaScript programming interface by defining \verb+anim['<label+ \verb+text>']+, which is a JavaScript reference to the animation object. The animation object provides a number of properties and methods that can be used for controlling the animation playback from within user defined JavaScript. For details, see Section~\ref{sect:api}.
 \begin{verbatim}
 type=[<file ext>]
 \end{verbatim}
@@ -375,7 +384,7 @@
 \begin{verbatim}
   [*]:[<frame rate>]:[<transparencies>][:<JavaScript>]
 \end{verbatim}
-While any field may be left blank, the first two colons are mandatory. The \verb+<JavaScript>+ field is explained on p.~\pageref{sect:jsfield}.
+While any field may be left blank, the first two colons are mandatory. The fourth field, \verb+<JavaScript>+, is explained on p.~\pageref{sect:jsfield}.
 
 An asterisk (`\verb+*+') in the leftmost field causes the animation to pause at that frame, very much as a \verb+\newframe*+ would do; a number in the second field changes the frame rate of the animation section that follows. In connection with the `\verb+timeline+' option, the asterisk extension and the optional \verb+<frame rate>+ argument of \verb+\newframe+ cease to make sense and will be tacitly ignored if present.
 
@@ -644,6 +653,7 @@
 \immediate\closeout\TimeLineFile
 %
 \animategraphics[
+  type=mps,
   width=0.8\linewidth,
   controls,
   loop,
@@ -1284,6 +1294,67 @@
 \end{document}
 \end{lstlisting}
 
+\section{Producing animated SVG} 
+Thanks to Martin Gieseking's `\verb+dvisvgm+' utility~\cite{dvisvgm} that ships with all major \TeX{} distributions, package `animate' can produce self-contained animated SVG, with all the bits and pieces already included that are necessary to run in modern Web browsers as standalone files or as embedded objects within a Web page made of HTML. Animations have the same look and usability, including optional control buttons, as if they were embedded in a PDF document.
+
+Moreover, as `\verb+dvisvgm+' is linked against the Ghostscript library, it can parse and convert embedded Postscript to inline SVG code. It is therefore compatible with the popular TikZ and PSTricks \LaTeX{} packages.
+ 
+SVG is a one-page graphics format. Therefore, it is most useful to first produce DVI with a single animation per file or page. Then, `\verb+dvisvgm+' converts every page of the DVI input to a standalone SVG file. For a standalone animated SVG, use the `article' document class and pass `\verb+dvisvgm+' as a global option. In this way, it gets conveyed to  `animate' and other packages to be loaded, such as `graphicx' or TikZ. Note that the `standalone' document class is not required; `\verb+dvisvgm+' already computes the tightly enclosing bounding box around the page content by default.
+
+The following code may serve as a template for generating standalone SVG:
+\begin{lstlisting}
+\documentclass[12pt,dvisvgm]{article}
+
+\usepackage{animate}
+\usepackage{graphicx}
+
+%\usepackage{xcolor}
+%\pagecolor{white} % opaque background with solid colour
+
+%\usepackage{pstricks} % enable as needed
+%\usepackage{tikz}
+
+\pagestyle{empty}
+
+\begin{document}
+\begin{center}
+
+%
+% \animategraphics{..}{...}{...}{...}
+%
+% or  
+%  
+% \begin{animateinline}{..} ... \end{animateinline} 
+%
+
+\end{center}
+\end{document}
+\end{lstlisting}
+Note that when animating external graphics with \verb+\animategraphics+, only Postscript (EPS, PS) files are converted to inline SVG code; files in other formats (SVG, PNG, JPEG) remain external and must be bundled with the final SVG output. Unfortunately, the use of (E)PS with \verb+\animategraphics+ is limited to vector graphics. If such files contain bitmapped content they must be converted to PNG (or JPEG, if photographs). Of course, these files remain external to the final animated SVG.
+
+Use one of
+\begin{verbatim}
+latex
+platex
+lualatex --output-format=dvi
+xelatex -no-pdf
+\end{verbatim}
+to produce DVI or XDV output from the \LaTeX{} source. After this, SVG is obtained by running
+\begin{verbatim}
+dvisvgm --no-fonts -exact
+\end{verbatim}
+on the intermediate DVI or XDV file. Option `\verb+--no-fonts+' prompts `\verb+dvisvgm+' to retrace font glyphs as graphical paths. It ensures that the text font looks as in normal PDF output. Option `\verb+--exact+' tells `\verb+dvisvgm+' to calculate exact bounding boxes around font glyphs. This avoids clipping of glyphs in the SVG output, as glyphs usually tend to be slightly bigger than their boxes defined in the font files. To convert multipage DVI/XDV with several animations, add option `\verb+-p1,-+'. By default, `\verb+dvisvgm+' processes only the very first page of the input file. As SVG derives from XML it is not known to be particularly economical in terms of file size. Compressed SVG, with file extension `\verb+svgz+', shortens download times and is supported by most Web browsers. It can be generated by adding option `\verb+-z+'.
+
+The recommended way to include animated SVG into HTML is to use the \verb+<object>+ tag. The \verb+<img>+ tag does not work here, as it ignores the embedded JavaScript. However, it may still be used as fallback. Also, it allows for search engine indexing, if desired:
+\begin{lstlisting}
+<object type="image/svg+xml" data="animatedImage.svg">
+  <!-- fallback & search engine indexing -->
+  <img src="animatedImage.svg" />
+</object>
+\end{lstlisting}
+
+In \TeX4ht documents, the whole \verb+<object>...</object>+ tag can be inserted by wrapping it in a \verb+\HCode{...}+ command.
+
 \section{Bugs}\label{sect:bugs}
 \begin{itemize}
   \item The maximum frame rate that can actually be achieved largely depends on the complexity of the graphics and on the available hardware. Starting with version 8, Acrobat Reader appears to be somewhat slower. However, you might want to experiment with the graphical hardware acceleration feature that was introduced in Reader 8. Go to menu `Edit' $\rightarrow$ `Preferences' $\rightarrow$ `Page Display' $\rightarrow$ `Rendering' to see whether hardware acceleration is available. A 2D GPU acceleration check box will be visible if a supported video card has been detected.
@@ -1347,6 +1418,7 @@
 
 \begin{thebibliography}{8}
   \bibitem{chupin} Chupin, M.: \emph{Syracuse MetaPost/Animations.} URL: \href{http://melusine.eu.org/syracuse/metapost/animations/chupin/?idsec=scara}{\url{http://melusine.eu.org/}} \href{http://melusine.eu.org/syracuse/metapost/animations/chupin/?idsec=scara}{\url{syracuse/metapost/animations/chupin/?idsec=scara}}
+\bibitem{dvisvgm} \emph{dvisvgm: A fast DVI to SVG converter} URL: \url{http://dvisvgm.de}
 \bibitem{gilg05} Gilg, J.: PDF-Animationen. In: \emph{Die \TeX nische Kom\"odie}, Issue 4, 2005, pp.~30--37
 %\bibitem{hol} Holeček, J.: \emph{Animations in a pdf\TeX-generated PDF}. URL: \url{http://www.fi.muni.cz/~xholecek/tex/pdfanim.xhtml}
 \bibitem{hol} Holeček, J.; Sojka, P.: Animations in pdf\TeX-generated PDF. In: \emph{\TeX, XML, and Digital Typography}, Springer, 2004, pp.~179--191. doi:10.1007/978-3-540-27773-6\textunderscore14

Modified: trunk/Master/texmf-dist/tex/latex/animate/animate.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/animate/animate.sty	2018-11-20 22:00:50 UTC (rev 49203)
+++ trunk/Master/texmf-dist/tex/latex/animate/animate.sty	2018-11-20 22:01:10 UTC (rev 49204)
@@ -8,14 +8,14 @@
 % graphics files or inline graphics (e. g. LaTeX-picture, PSTricks,
 % pgf/TikZ, ...)
 
-% Supports LaTeX->dvips->ps2pdf, (Xe)LaTeX->(x)dvipdfmx, LuaLaTeX and
-% pdfLaTeX workflows.
+% Supports LaTeX->dvips->ps2pdf, (Xe)LaTeX->(x)dvipdfmx, LuaLaTeX,
+% pdfLaTeX and LaTeX->dvisvgm workflows.
 
 \NeedsTeXFormat{LaTeX2e}
 
-\def\@anim at version{2018/08/22}
+\def\@anim at version{2018/11/20}
 \ProvidesPackage{animate}
-[\@anim at version\space PDF animations from files and inline graphics]
+[\@anim at version\space PDF & SVG animations from files and inline graphics]
 
 \RequirePackage{xkeyval}
 \RequirePackage{ifthen}
@@ -24,7 +24,6 @@
 \RequirePackage{ifxetex}
 \RequirePackage{ifdraft}
 \RequirePackage{calc}
-\RequirePackage{graphics}%\scalebox, \resizebox, \rotatebox
 
 %driver options (the only package options we process immediately)
 \newboolean{@anim at dvips}
@@ -31,6 +30,8 @@
 \setboolean{@anim at dvips}{false}
 \newboolean{@anim at dvipdfmx}
 \setboolean{@anim at dvipdfmx}{false}
+\newboolean{@anim at dvisvgm}
+\setboolean{@anim at dvisvgm}{false}
 \ifpdf\else
   \setboolean{@anim at dvips}{true}% default dvi mode
   \setboolean{@anim at dvipdfmx}{false}
@@ -42,6 +43,7 @@
     \setboolean{@anim at dvipdfmx}{true}
     \setboolean{@anim at dvips}{false}
     \PassOptionsToPackage{dvipdfmx}{pdfbase}
+    \PassOptionsToPackage{dvipdfmx}{graphics}
   }
   \DeclareOptionX{xetex}{%
     \setboolean{@anim at dvipdfmx}{true}
@@ -48,6 +50,18 @@
     \setboolean{@anim at dvips}{false}
     \PassOptionsToPackage{xetex}{pdfbase}
   }
+  \DeclareOptionX{dvisvgm}{%
+    \@ifclassloaded{standalone}{
+      \PackageError{animate}{%
+        Option `dvisvgm' and the `standalone' document\MessageBreak%
+        class are not compatible.\MessageBreak%
+        Use another document class, such as `article'%
+      }{}%
+    }{}%
+    \setboolean{@anim at dvisvgm}{true}
+    \setboolean{@anim at dvips}{false}
+    \PassOptionsToPackage{dvisvgm}{graphics}
+  }
 \fi
 \newboolean{@anim at xetex}
 \setboolean{@anim at xetex}{false}
@@ -66,7 +80,58 @@
 }{%
   \global\@anim at insideexportfalse%
 }
-\DeclareOptionX{export}{%
+\DeclareOptionX{export}{\setboolean{@anim at export}{true}}
+
+\DeclareOptionX*{}\ProcessOptionsX*\relax %allow anything as an option
+%(remaining package options will be processed near end of this file)
+
+\RequirePackage{graphics}%\scalebox, \resizebox, \rotatebox
+
+\if at anim@dvisvgm
+  \setboolean{@anim at export}{false}
+
+  \AtBeginDocument{%
+    %bring back PS file inclusion
+    \ifdefined\Ginclude at eps\else%
+      \def\Gin at extensions{.svg,.eps,.png,.jpg,.jpeg}%
+      \def\Ginclude at eps#1{%
+       \message{<#1>}%
+        \bgroup
+        \def\@tempa{!}%
+        \dimen@\Gin at req@width
+        \dimen at ii.1bp%
+        \divide\dimen@\dimen at ii
+        \@tempdima\Gin at req@height
+        \divide\@tempdima\dimen at ii
+          \special{PSfile="#1"\GPT at space
+            llx=\Gin at llx\GPT at space
+            lly=\Gin at lly\GPT at space
+            urx=\Gin at urx\GPT at space
+            ury=\Gin at ury\GPT at space
+            \ifx\Gin at scalex\@tempa\else rwi=\number\dimen@\GPT at space\fi
+            \ifx\Gin at scaley\@tempa\else rhi=\number\@tempdima\GPT at space\fi
+            \ifGin at clip clip\fi}%
+        \egroup}%
+      \@namedef{Gin at rule@.ps}#1{{eps}{.ps}{#1}}%
+      \@namedef{Gin at rule@.eps}#1{{eps}{.eps}{#1}}%
+      \@namedef{Gin at rule@.mps}#1{{eps}{.mps}{#1}}%
+    \fi%
+    %restore PS scaling and rotation
+    \def\Grot at start{%
+      \special{ps: gsave currentpoint
+        currentpoint translate \Grot at angle\GPT at space neg
+        rotate neg exch neg exch translate}}%
+    \def\Grot at end{\special{ps: currentpoint grestore moveto}}%
+    \def\Gscale at start{\special{ps:  currentpoint currentpoint translate
+      \Gscale at x\GPT at space \Gscale at y\GPT at space scale neg exch neg exch
+      translate}}%
+    \def\Gscale at end{\special{ps:  currentpoint currentpoint translate
+      1 \Gscale at x\GPT at space div 1 \Gscale at y\GPT at space div scale
+      neg exch neg exch translate}}%
+  }
+\fi
+
+\if at anim@export
   \@ifclassloaded{standalone}{}{
     \PackageError{animate}{%
       Option `export' requires `standalone' document class.\MessageBreak%
@@ -77,24 +142,90 @@
       at the beginning of the document preamble.%
     }%
   }%
-  \setboolean{@anim at export}{true}
   \standaloneenv{anim at export}
-}
+\fi
 
-\DeclareOptionX*{}\ProcessOptionsX*\relax %allow anything as an option
-%(remaining package options will be processed near end of this file)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% low level PDF/SVG operations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\if at anim@dvisvgm
+  \RequirePackage{expl3}
+  \ExplSyntaxOn
+  \let\@anim at fpeval\fp_eval:n
+  \ExplSyntaxOff
 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\RequirePackage{pdfbase}%low level PDF operations
-\@ifpackagelater{pdfbase}{2017/09/29}{}{
-  \PackageError{animate}{%
-    Support package `pdfbase.sty' too old.%
-  }{%
-    Please install an up to date version of `pdfbase.sty'.\MessageBreak%
-    Aborting.%
-  }%
-}
-\ExplSyntaxOn
+  \setboolean{@anim at export}{false}
+  \newcount\@anim at objnum
+  \edef\@anim at hash{\string#}
+
+  \def\@anim at xform#1#2#3#4#5{%
+    \makebox[\z@][l]{\raisebox{\z@}[\z@][\z@]{%
+      \special{dvisvgm:raw {?nl}<defs>{?nl}%
+        <g transform='translate(-{?x},-{?y})' #4 id='obj\the\@anim at objnum'
+          class='xform'>%
+      }%
+      \box#5%
+      \special{dvisvgm:raw {?nl}</g>{?nl}</defs>}%
+    }}%
+    \xdef\@anim at lastxform{\@anim at hash obj\the\@anim at objnum}%
+    \global\advance\@anim at objnum by \@ne%
+  }
+  \def\@anim at refxform#1{%
+    \special{dvisvgm:raw
+      {?nl}<use x='{?x}' y='{?y}' xlink:href='#1'/>%
+    }%
+  }
+
+  \def\@anim at updatebbox#1#2#3{\special{dvisvgm:bbox #1 #2 #3}}
+
+  \def\@anim at annot#1#2#3#4{%
+    \special{dvisvgm:raw {?nl}<path d=}%
+      \begingroup\setlength\unitlength{1pt}%
+      \begin{picture}(0,0)% mark annotation rectangle
+        \put(0,-\strip at pt\dimexpr#3\relax){% ll
+          \special{dvisvgm:raw 'M{?x} {?y}}%
+        }%
+        \put(\strip at pt\dimexpr#1\relax,-\strip at pt\dimexpr#3\relax){% lr
+          \special{dvisvgm:raw {?nl}L{?x} {?y}}%
+        }%
+        \put(\strip at pt\dimexpr#1\relax,\strip at pt\dimexpr#2\relax){% ur
+          \special{dvisvgm:raw {?nl}L{?x} {?y}}%
+        }%
+        \put(0,\strip at pt\dimexpr#2\relax){% ul
+          \special{dvisvgm:raw {?nl}L{?x} {?y} Z'}%
+        }%
+      \end{picture}%
+      \endgroup%
+    \special{dvisvgm:raw {?nl}opacity='0' #4/>}%
+  }
+
+  %approach similar to OCGs, that is, putting the frame content in an svg group,
+  % <g id='...'>...</g>, whose visibility is then manipulated by JavaScript
+  \def\@anim at newocg#1#2{\xdef\@anim at curocg{id='#1.#2' class='ocg'}}
+  \def\ocgbase at add@to at off@list#1{%
+    \xdef\@anim at curocg{\@anim at curocg\space visibility='hidden'}%
+  }
+  \def\ocgbase at oc@bdc#1{\special{dvisvgm:raw {?nl}<g #1>}}
+  \def\ocgbase at oc@emc{\special{dvisvgm:raw {?nl}</g>}}
+
+  \def\@anim at literal#1#2{%
+    % #1: {} --> current location becomes (0,0), unit vectors 1bp right and up,
+    %            graphics state saved before and restored after the code in #2
+    % #1: {direct|page} --> no origin translation, no saving of gr. state
+    % #2: raw postscript
+    \ifx\empty#1\empty\special{" #2}\else\special{ps:: #2}\fi%
+  }
+\else
+  \RequirePackage{pdfbase}
+  \@ifpackagelater{pdfbase}{2017/09/29}{}{
+    \PackageError{animate}{%
+      Support package `pdfbase.sty' too old.%
+    }{%
+      Please install an up to date version of `pdfbase.sty'.\MessageBreak%
+      Aborting.%
+    }%
+  }
+  \ExplSyntaxOn
   \let\@anim at literal\pbs_literal:nn
 
   \def\@anim at dictobj#1{
@@ -119,11 +250,11 @@
 
   \let\@anim at refxform\pbs_pdfrefxform:n
 
-  \def\@anim at pdfannot#1#2#3#4{
+  \def\@anim at annot#1#2#3#4{
     \pbs_pdfannot:nnnn{#1}{#2}{#3}{#4}
   }
 
-  \def\@anim at pdfwid#1#2#3#4{
+  \def\@anim at widget#1#2#3#4{
     \pbs_pdfannot:nnnn{#1}{#2}{#3}{#4}
     \pbs_appendtofields:n{\pbs_pdflastann:}
   }
@@ -131,26 +262,29 @@
   \let\@anim at pdfcatalog\pbs_pdfcatalog:n
 
   \let\@anim at fpeval\fp_eval:n
-\ExplSyntaxOff
+  \ExplSyntaxOff
+
+  \RequirePackage{ocgbase} %OCG generating and configuration macros
+  \def\@anim at newocg#1#2{%#1:@anim at num, #2:@anim at curframe@zb
+    \ocgbase at new@ocg{#1.#2}{}{1}%
+    \xdef\@anim at curocg{\ocgbase at last@ocg}%
+  }
+\fi
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-\RequirePackage{ocgbase} %OCG generating and configuration macros
-\def\@anim at newocg#1#2{%#1:@anim at num, #2:@anim at curframe@zb
-  \ocgbase at new@ocg{#1.#2}{}{1}%
-  \xdef\@anim at curocg{\ocgbase at last@ocg}%
-}
-
 \ifpdf\else
-  \if at anim@dvipdfmx\else % dvips
-    %if geometry package is loaded, execute `\geometry{dvips}' right before
-    %  `\begin{document}'; not sure whether needed at all any more
-    \let\@anim at document\document
-    \def\document{%
-      \endgroup%
-      \@ifpackageloaded{geometry}{\geometry{dvips}}{}%
-      \begingroup%
-      \@anim at document%
-    }
+  \if at anim@dvipdfmx\else
+    \if at anim@dvisvgm\else % dvips
+      %if geometry package is loaded, execute `\geometry{dvips}' right before
+      %  `\begin{document}'; not sure whether still needed at all
+      \let\@anim at document\document
+      \def\document{%
+        \endgroup%
+        \@ifpackageloaded{geometry}{\geometry{dvips}}{}%
+        \begingroup%
+        \@anim at document%
+      }
+    \fi
   \fi
 \fi
 
@@ -219,8 +353,12 @@
   \gdef\@anim at lscape{}%
   \gdef\@anim@@lscape{:ls}%
   \ifdefined\landscape%
-    \g at addto@macro{\landscape}{\gdef\@anim at lscape{:ls}}%
-    \g at addto@macro{\endlandscape}{\gdef\@anim at lscape{}}%
+%    \if at anim@dvisvgm% disable `landscape' environment
+%      \renewenvironment{landscape}{}{}%
+%    \else%
+      \g at addto@macro{\landscape}{\gdef\@anim at lscape{:ls}}%
+      \g at addto@macro{\endlandscape}{\gdef\@anim at lscape{}}%
+%    \fi%
   \fi%
 }
 
@@ -229,6 +367,7 @@
 % true if any of `controls' or `palindrome' or `label' options is set
 \newboolean{@anim at timeline} %true if `timeline' option is set
 \newboolean{@anim at multipage} % multipage document?
+\newboolean{@anim at nomouse} % animation widget to react on mouse events?
 
 \newbox\@anim at box %stores animation frames
 \newbox\@anim at measbox % for measuring purposes
@@ -244,19 +383,19 @@
 \def\@anim at xformnatdp#1{\expandafter\@anim at thirdofthree#1}
 
 %helper macro that typesets graphics file into savebox
-\if at anim@dvips % dvips: no multi-page support
-  \def\@anim at filebox#1#2{% pdftex, xetex
-    \edef\@anim at curfile{[clip\@anim at gropts]{#1}}%
-    \global\setbox\@anim at box=\hbox{%
-      \expandafter\includegraphics\@anim at curfile}%
-  }
-\else %pdfTeX, LuaTeX, dvipdfmx, xetex (multi-page)
+\def\@anim at filebox#1#2{% dvips, dvisvgm: no multi-page support
+  \edef\@anim at curfile{[clip\@anim at gropts]{#1}}%
+  \global\setbox\@anim at box=\hbox{%
+    \expandafter\includegraphics\@anim at curfile}%
+}
+\if at anim@dvips\else\if at anim@dvisvgm\else
+  %pdfTeX, LuaTeX, dvipdfmx, xetex (multi-page)
   \def\@anim at filebox#1#2{%
     \edef\@anim at curfile{[clip\@anim at gropts,page=#2]{#1}}%
     \global\setbox\@anim at box=\hbox{%
       \expandafter\includegraphics\@anim at curfile}%
   }
-\fi
+\fi\fi
 
 \def\@anim at checkboxsize#1#2{% #1: box number, #2: file
   \ifdim\wd#1=\z@%
@@ -279,78 +418,101 @@
 
 %create Form XObject from graphics file
 \def\@anim at ximage#1#2#3#4{%#1:@anim at num, #2:@anim at curframe@zb, #3:filename,
-  %#4: page number of multipage file
-  \edef\@anim at fingerprint{file:\@anim at pdfmdfivesum{#3}.#4.\@anim at gropts}%
-  \edef\@anim at curxform{\@anim at getkeyval{\@anim at fingerprint}}%
+  %                                        #4: page number of multipage file
+  \if at anim@dvisvgm%
+    % with dvisvgm, final animation dims must be passed to includegraphics;
+    % otherwise, final bbox of the document may be wrong, in particular in the
+    % case of standalone animations with downscaled graphics
+    \ifnum#2=\z@\relax%
+      \@anim at filebox{#3}{#4}% store file in a box
+      \@anim at scale\@anim at box% get final dimensions of animation widget
+      %prevent later re-scaling
+      \gdef\@anim at widtharg{\width}%
+      \gdef\@anim at heightarg{\height}%
+      \gdef\@anim at totheightarg{\totalheight}%
+      \gdef\@anim at boxscale{\@ne}%
+      %append final dims to inclusion opts, also used for the remaining files
+      %of the current animation
+      \xdef\@anim at gropts{\@anim at gropts,width=\@anim at animwidth%
+        ,height=\@anim at animheight,totalheight=\@anim at animtotalheight}%
+    \fi%
+  \fi%
+  % fingerprint "<file chksum>.<page>.<graphicx opts>" for external graphics
+  % for preventing re-embedding
+  \edef\@anim at fingerprint{\@anim at pdfmdfivesum{#3}.#4.\@anim at gropts}%
+  \edef\@anim at curxform{\@anim at getkeyval{xform:\@anim at fingerprint}}%
   \ifthenelse{\equal{\@anim at curxform}{}}{%
-    % new file.page.graphicx_options
+    % new "<file chksum>.<page>.<graphicx opts>"
     \@anim at filebox{#3}{#4}% store file in a box
-    \@anim at xinline{#1}{#2}{\@anim at box}{!}% delegate Form XObject creation
-    \@anim at newkey{\@anim at fingerprint}{\@anim@@lastxform}%
+    \@anim at newkey{natdims:\@anim at fingerprint}{%
+      {\the\wd\@anim at box}{\the\ht\@anim at box}{\the\dp\@anim at box}%
+    }%
+    \@anim at xinline{#1}{#2}{\@anim at box}{newfile}% delegate Form XObject creation
+    \@anim at newkey{xform:\@anim at fingerprint}{\@anim@@lastxform}%
   }{% file known, re-using existing form xobject
-    \edef\@anim at curndims{\@anim at getkeyval{natdims:\@anim at curxform}}% nat. dims
+    \edef\@anim at curndims{\@anim at getkeyval{natdims:\@anim at fingerprint}}%
     \setbox\@anim at box=\hbox to \@anim at xformnatwd{\@anim at curndims}{%
       \vrule width \z@
         height \@anim at xformnatht{\@anim at curndims}
-        depth \@anim at xformnatdp{\@anim at curndims}\hss%
+        depth \@anim at xformnatdp{\@anim at curndims}%
+        \@anim at refxform{\@anim at curxform}%
+        \hss%
     }%
-    \@anim at xinline{#1}{#2}{\@anim at box}{\@anim at curxform}%
+    \global\let\@anim@@lastxform\@anim at curxform%
+    \@anim at xinline{#1}{#2}{\@anim at box}{knownfile}%
   }%
 }
 
 %creates Form XObject from box contents
 \def\@anim at xinline#1#2#3#4{%
+  \edef\@anim at status{#4}% "newfile", "knownfile" or "inline" (inline graphics)
   \edef\@anim at curwd{\the\wd#3}%
   \edef\@anim at curht{\the\ht#3}%
   \edef\@anim at curdp{\the\dp#3}%
   \ifnum#2=\z@\relax%
-    %nat. dims of zeroth frame
-    \xdef\@anim at zframewd{\@anim at curwd}%
-    \xdef\@anim at zframeht{\@anim at curht}%
-    \xdef\@anim at zframedp{\@anim at curdp}%
-    %determine size of animation widget
+    %measure 0th frame
     \setbox\@anim at measbox=\hbox to \wd#3{%
       \vrule width \z@ height \ht#3 depth \dp#3\hss}%
+    %determine final dims of animation widget
     \@anim at scale{\@anim at measbox}%
-  \else%
-    \def\@anim at needresize{0}%
-    %test if natural dimensions of the current frame differ from those
-    %of the 0th frame
-    \ifdim\wd#3=\@anim at zframewd\else\def\@anim at needresize{1}\fi%
-    \ifdim\ht#3=\@anim at zframeht\else\def\@anim at needresize{1}\fi%
-    \ifdim\dp#3=\@anim at zframedp\else\def\@anim at needresize{1}\fi%
   \fi%
-  %create form xobject from box argument
-  \ifthenelse{\equal{#4}{!}}{% %%%% new graphics %%%%
-    %put graphics into XObject
-    \@anim at xform{1}{0}{}{}{#3}%
-    \xdef\@anim@@lastxform{\@anim at lastxform}%
-    \@anim at newkey{natdims:\@anim at lastxform}{%
-      {\@anim at curwd}{\@anim at curht}{\@anim at curdp}%
+  %test if natural dimensions of the current frame differ from
+  %final widget size
+  \def\@anim at needresize{0}%
+  \ifdim\@anim at curwd=\@anim at animwidth\else\def\@anim at needresize{1}\fi%
+  \ifdim\@anim at curht=\@anim at animheight\else\def\@anim at needresize{1}\fi%
+  \ifdim\@anim at curdp=\@anim at animdepth\else\def\@anim at needresize{1}\fi%
+  %if it's a new file, make xobject from it at its natural size
+  \ifthenelse{\equal{\@anim at status}{newfile}}{%
+    \@anim at xform{1}{0}{}{}{#3}% `{1}'-->with additional resources (opacity etc.)
+    \global\let\@anim@@lastxform\@anim at lastxform%
+    \def\@anim at status{knownfile}%
+    \global\setbox#3=\hbox to \@anim at curwd{%
+      \vrule width \z@ height \@anim at curht depth \@anim at curdp%
+      \@anim at refxform{\@anim at lastxform}%
+      \hss%
     }%
-  }{%
-    \xdef\@anim at lastxform{#4}%
-  }%
-  \ifnum#2>\z@\relax%
-    %adjust size of current frame to zeroth frame's dims, if necessary
-    \ifnum\@anim at needresize>\z@\relax%
-      \global\setbox#3=\hbox to \@anim at curwd{%
-        \vrule width \z@ height \@anim at curht depth \@anim at curdp%
-        \noexpand\@anim at refxform{\@anim at lastxform}%
-        \hss%
+  }{}%
+  %adjust size of current frame to final animation dims, if necessary
+  \ifnum\@anim at needresize>\z@\relax%
+    \global\setbox#3=\hbox{%
+      \raisebox{-\@anim at animdepth}{%
+        \resizebox*{\@anim at animwidth}{%
+          \@anim at animtotalheight}{\raisebox{\depth}{\box#3}}%
       }%
-      \global\setbox#3=\hbox{%
-        \raisebox{-\@anim at zframedp}{%
-          \resizebox*{\@anim at zframewd}{%
-            \dimexpr\@anim at zframeht+\@anim at zframedp\relax%
-          }{\raisebox{\depth}{\box#3}}%
-        }%
-      }%
-      \@anim at xform{0}{0}{}{}{#3}%
-    \fi%
+    }%
+    \ifthenelse{\equal{\@anim at status}{knownfile}}{%
+      \@anim at xform{0}{0}{}{}{#3}% without additional Resources
+      \global\let\@anim@@lastxform\@anim at lastxform%
+    }{}%
   \fi%
+  %distill box with inline graphics to xobject
+  \ifthenelse{\equal{\@anim at status}{inline}}{%
+    \@anim at xform{1}{0}{}{}{#3}% with additional Resources
+    \global\let\@anim@@lastxform\@anim at lastxform%
+  }{}%
   %keep a record of XObject number
-  \@anim at newkey{img@#2}{\@anim at lastxform}%
+  \@anim at newkey{img@#2}{\@anim@@lastxform}%
   \if at anim@timeline\else%
     \@anim at newkey{frmcontent@#2}{\@anim at getkeyval{img@#2},}%
     \@anim at makeframe{#1}{#2}%
@@ -373,12 +535,12 @@
 % \ifcase\@anim at method as
 % 0 & 1: non-interactive Widget annotation
 % 2: Form XObject referenced in the page content, tagged as OC
-% animation
+% or dvisvgm
 \def\@anim at makeframe#1#2{%
   %container box
   \edef\@anim at tmpvar{\@anim at getkeyval{frmcontent@#2},}%
-  \global\setbox\@anim at box=\hbox to \@anim at zframewd{%
-    \vrule width \z@ height \@anim at zframeht depth \@anim at zframedp%
+  \global\setbox\@anim at box=\hbox to \@anim at animwidth{%
+    \vrule width \z@ height \@anim at animheight depth \@anim at animdepth%
     \expandafter\@anim at insertfrmcontent\@anim at tmpvar\@nil%
     \hss%
   }%
@@ -394,15 +556,15 @@
     %initial visibility
     \ifnum\@anim at poster>\@anim at mtwo\relax% insert poster frame
       \ifnum#2=\@anim at poster\relax%
-        \edef\@anim at posterap{\@anim at lastxform}%
+        \let\@anim at posterap\@anim at lastxform%
       \else%
         \ifnum\@anim at poster=\@anim at mone\relax% use last frame as poster
-          \edef\@anim at posterap{\@anim at lastxform}%
+          \let\@anim at posterap\@anim at lastxform%
         \fi%
       \fi%
     \fi%
     %insert (invisible) widget with current frame as appearance
-    \@anim at pdfwid{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
+    \@anim at widget{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
       /Subtype/Widget%
       /F 2%
       /FT/Btn/Ff 65537%
@@ -430,7 +592,7 @@
     \fi%
     %frame insertion
     \@anim at xform{0}{1}{}{}{\@anim at box}%
-    \@anim at pdfwid{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
+    \@anim at widget{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
       /Subtype/Widget%
       \@anim at annotflag%
       /FT/Btn/Ff 65537%
@@ -439,8 +601,11 @@
       /MK <</TP 1/I \@anim at lastxform/IF<</S/A/FB true>>>>%
       /T (#1.#2)%
     }%
-  \or% ocg based
-    \if at anim@export\else%
+  \or% ocg based (abused for dvisvgm backend as well as for
+    % multipage PDF export)
+    \if at anim@export%
+      \box\@anim at box%
+    \else%
       \@anim at newocg{#1}{#2}%
       %initial visibility
       \ifnum\@anim at poster=\@anim at mone\relax% use last frame as poster
@@ -455,41 +620,30 @@
           \ocgbase at add@to at off@list{\@anim at curocg}%
         \fi%
       \fi%
-    \fi%
-    \def\@anim at needresize{0}%
-    \ifdim\@anim at animwidth=\@anim at zframewd\else%
-      \def\@anim at needresize{1}\fi%
-    \ifdim\@anim at animheight=\@anim at zframeht\else%
-      \def\@anim at needresize{1}\fi%
-    \ifdim\@anim at animdepth=\@anim at zframedp\else%
-      \def\@anim at needresize{1}\fi%
-    \ifnum\@anim at needresize>\z@\relax%
-      \global\setbox\@anim at box=\hbox{%
-        \raisebox{-\@anim at animdepth}{%
-          \resizebox*{\@anim at animwidth}{%
-            \dimexpr\@anim at animheight+\@anim at animdepth\relax%
-          }{\raisebox{\depth}{\box\@anim at box}}%
-        }%
-      }%
-    \fi%
-    \if at anim@export%
-      \box\@anim at box%
-    \else%
       %frame insertion
-      % /OC method
-      \@anim at xform{0}{0}{}{/OC \@anim at curocg}{\@anim at box}%
-      \@anim at refxform{\@anim at lastxform}%
-%      % marked content method
-%      \@anim at xform{0}{0}{}{}{\@anim at box}%
-%      \ocgbase at oc@bdc{\@anim at curocg}%
-%      \@anim at refxform{\@anim at lastxform}%
-%      \ocgbase at oc@emc%
+      \if at anim@dvisvgm%
+        % `marked content' method for dvisvgm
+        \@anim at xform{0}{0}{}{}{\@anim at box}%
+        \ocgbase at oc@bdc{\@anim at curocg}%
+        \@anim at refxform{\@anim at lastxform}%
+        \ocgbase at oc@emc%
+      \else%
+        % /OC method for PDF output
+        \@anim at xform{0}{0}{}{/OC \@anim at curocg}{\@anim at box}%
+        \@anim at refxform{\@anim at lastxform}%
+        %% `marked content' method (slower, perhaps)
+        %\@anim at xform{0}{0}{}{}{\@anim at box}%
+        %\ocgbase at oc@bdc{\@anim at curocg}%
+        %\@anim at refxform{\@anim at lastxform}%
+        %\ocgbase at oc@emc%
+      \fi%
     \fi%
   \fi%
 }
 
 %create XObjects of all button faces
-\if at anim@dvips
+\ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1
+  %dvips .OR. dvisvgm
   %stroking commands
   \def\@anim at btnend{%
     \@anim at fg\space
@@ -686,68 +840,106 @@
     11.5 7.5 lineto
     stroke
   }
-  \def\@anim at makebuttons#1{% #1: @anim at num
-    \@anim at xbutton{EndLeft}{%
-      [-1 0 0 1 15 0] concat
-      \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
-    \@anim at btnend}{#1}%
-    \@anim at xbutton{EndRight}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnend}{#1}%
-    \@anim at xbutton{Minus}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnminus}{#1}%
-    \@anim at xbutton{PauseLeft}{%
-      [-1 0 0 1 15 0] concat
-      \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
-      \@anim at btnpause}{#1}%
-    \@anim at xbutton{PauseRight}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnpause}{#1}%
-    \@anim at xbutton{PlayLeft}{%
-      [-1 0 0 1 15 0] concat
-      \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
-      \@anim at btnplay}{#1}%
-    \@anim at xbutton{PlayRight}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnplay}{#1}%
-    \@anim at xbutton{Plus}{\@anim at btnplus}{#1}%
-    \@anim at xbutton{Reset}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnreset}{#1}%
-    \@anim at xbutton{StepLeft}{%
-      [-1 0 0 1 15 0] concat
-      \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
-      \@anim at btnstep}{#1}%
-    \@anim at xbutton{StepRight}{%
-      \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
-      \@anim at btnstep}{#1}%
+  \def\@anim at makebutton#1#2{% #1: name ; #2: current colour combination
+    \edef\@anim at arg{#1}%
+    \ifx\@anim at EndLeft\@anim at arg%
+      \@anim at xbutton{EndLeft}{%
+        [-1 0 0 1 15 0] concat
+        \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
+        \@anim at btnend}{#2}%
+    \fi%
+    \ifx\@anim at EndRight\@anim at arg%
+      \@anim at xbutton{EndRight}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnend}{#2}%
+    \fi%
+    \ifx\@anim at Minus\@anim at arg%
+      \@anim at xbutton{Minus}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnminus}{#2}%
+    \fi%
+    \ifx\@anim at PauseLeft\@anim at arg%
+      \@anim at xbutton{PauseLeft}{%
+        [-1 0 0 1 15 0] concat
+        \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
+        \@anim at btnpause}{#2}%
+    \fi%
+    \ifx\@anim at PauseRight\@anim at arg%
+      \@anim at xbutton{PauseRight}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnpause}{#2}%
+    \fi%
+    \ifx\@anim at PlayLeft\@anim at arg%
+      \@anim at xbutton{PlayLeft}{%
+        [-1 0 0 1 15 0] concat
+        \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
+        \@anim at btnplay}{#2}%
+    \fi%
+    \ifx\@anim at PlayRight\@anim at arg%
+      \@anim at xbutton{PlayRight}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnplay}{#2}%
+    \fi%
+    \ifx\@anim at Plus\@anim at arg%
+      \@anim at xbutton{Plus}{\@anim at btnplus}{#2}%
+    \fi%
+    \ifx\@anim at Reset\@anim at arg%
+      \@anim at xbutton{Reset}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnreset}{#2}%
+    \fi%
+    \ifx\@anim at StepLeft\@anim at arg%
+      \@anim at xbutton{StepLeft}{%
+        [-1 0 0 1 15 0] concat
+        \ifx\@anim at lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi%
+        \@anim at btnstep}{#2}%
+    \fi%
+    \ifx\@anim at StepRight\@anim at arg%
+      \@anim at xbutton{StepRight}{%
+        \ifx\@anim at lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi%
+        \@anim at btnstep}{#2}%
+    \fi%
   }
-  \def\@anim at xbutton#1#2#3{% #1: name; #2: stroking commands, #3 @anim at num
-    \global\setbox\@anim at box=\hbox to 15bp {\vbox to 15bp {\vss%
-      \@anim at literal{}{#2}%
-    }\hss}%
-    %distill box into XObject
-    \@anim at xform{0}{1}{}{%
-      \ifx\empty\@anim at alpha\empty\else/Group <</S/Transparency>>\fi%
-    }{\@anim at box}%
-    %nested XObject if transparency is to be added
-    \ifx\empty\@anim at alpha\empty\else%
+  \def\@anim at xbutton#1#2#3{% #1: name; #2: stroking commands, #3 current colour
+    \ifcsname btn#1:#3\endcsname\else%                            % combination
+      % only create if button face doesn't exist yet
       \global\setbox\@anim at box=\hbox to 15bp {\vbox to 15bp {\vss%
-        \@anim at literal{direct}{%
-          /.setopacityalpha where {%
-            %Ghostscript
-            pop \@anim at alpha\space .setopacityalpha%
-          }{%
-            %Distiller
-            mark /CA \@anim at alpha /ca \@anim at alpha /SetTransparency pdfmark%
-          } ifelse%
-        }%
-        \@anim at refxform{\@anim at lastxform}%
+        \@anim at literal{}{#2}%
       }\hss}%
-      \@anim at xform{0}{0}{}{}{\@anim at box}%
+      \if at anim@dvisvgm%
+        \global\setbox\@anim at box=\hbox{%
+          \resizebox*{!}{\@anim at btnsize}{\box\@anim at box}}%
+      \fi%
+      %distill box into XObject
+      \@anim at xform{0}{1}{}{%
+        \ifx\empty\@anim at alpha\empty\else%
+          \if at anim@dvisvgm%
+            opacity='\@anim at alpha'%
+          \else%
+            /Group <</S/Transparency>>%
+          \fi%
+        \fi%
+      }{\@anim at box}%
+      %nested XObject if transparency is to be added
+      \if at anim@dvisvgm\else%
+        \ifx\empty\@anim at alpha\empty\else%
+          \global\setbox\@anim at box=\hbox to 15bp {\vbox to 15bp {\vss%
+            \@anim at literal{direct}{%
+              /.setopacityalpha where {%
+                %Ghostscript
+                pop \@anim at alpha\space .setopacityalpha%
+              }{%
+                %Distiller
+                mark /CA \@anim at alpha /ca \@anim at alpha /SetTransparency pdfmark%
+              } ifelse%
+            }%
+            \@anim at refxform{\@anim at lastxform}%
+          }\hss}%
+          \@anim at xform{0}{0}{}{}{\@anim at box}%
+        \fi%
+      \fi%
+      \@anim at newkey{btn#1:#3}{\@anim at lastxform}%
     \fi%
-    \@anim at newkey{btn#1:#3}{\@anim at lastxform}%
   }
 \else %pdftex/dvipdfmx/xetex
   %stroking commands
@@ -931,84 +1123,109 @@
     115 75 l
     S
   }
-  \def\@anim at makebuttons#1{%
-    \@anim at xbutton{EndLeft}{%
-      q -0.1 0 0 0.1 15 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
-      \@anim at btnend\space Q%
-    }{#1}%
-    \@anim at xbutton{EndRight}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnend\space Q%
-    }{#1}%
-    \@anim at xbutton{Minus}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnminus\space Q%
-    }{#1}%
-    \@anim at xbutton{PauseLeft}{%
-      q -0.1 0 0 0.1 15 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
-      \@anim at btnpause\space Q%
-    }{#1}%
-    \@anim at xbutton{PauseRight}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnpause\space Q%
-    }{#1}%
-    \@anim at xbutton{PlayLeft}{%
-      q -0.1 0 0 0.1 15 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
-      \@anim at btnplay\space Q%
-    }{#1}%
-    \@anim at xbutton{PlayRight}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnplay\space Q%
-    }{#1}%
-    \@anim at xbutton{Plus}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \@anim at btnplus\space Q%
-    }{#1}%
-    \@anim at xbutton{Reset}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnreset\space Q%
-    }{#1}%
-    \@anim at xbutton{StepLeft}{%
-      q -0.1 0 0 0.1 15 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
-      \@anim at btnstep\space Q%
-    }{#1}%
-    \@anim at xbutton{StepRight}{%
-      q 0.1 0 0 0.1 0 0 cm
-      \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
-      \@anim at btnstep\space Q%
-    }{#1}%
+  \def\@anim at makebutton#1#2{% #1: name ; #2: current colour combination
+    \edef\@anim at arg{#1}%
+    \ifx\@anim at EndLeft\@anim at arg%
+      \@anim at xbutton{EndLeft}{%
+        q -0.1 0 0 0.1 15 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
+        \@anim at btnend\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at EndRight\@anim at arg%
+      \@anim at xbutton{EndRight}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnend\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at Minus\@anim at arg%
+      \@anim at xbutton{Minus}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnminus\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at PauseLeft\@anim at arg%
+      \@anim at xbutton{PauseLeft}{%
+        q -0.1 0 0 0.1 15 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
+        \@anim at btnpause\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at PauseRight\@anim at arg%
+      \@anim at xbutton{PauseRight}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnpause\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at PlayLeft\@anim at arg%
+      \@anim at xbutton{PlayLeft}{%
+        q -0.1 0 0 0.1 15 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
+        \@anim at btnplay\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at PlayRight\@anim at arg%
+      \@anim at xbutton{PlayRight}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnplay\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at Plus\@anim at arg%
+      \@anim at xbutton{Plus}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \@anim at btnplus\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at Reset\@anim at arg%
+      \@anim at xbutton{Reset}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnreset\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at StepLeft\@anim at arg%
+      \@anim at xbutton{StepLeft}{%
+        q -0.1 0 0 0.1 15 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi%
+        \@anim at btnstep\space Q%
+      }{#2}%
+    \fi%
+    \ifx\@anim at StepRight\@anim at arg%
+      \@anim at xbutton{StepRight}{%
+        q 0.1 0 0 0.1 0 0 cm
+        \ifx\@anim at lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi%
+        \@anim at btnstep\space Q%
+      }{#2}%
+    \fi%
   }
   %XObject creation
   \def\@anim at xbutton#1#2#3{% #1 name, #2 stroking commands, #3 @anim at num
-    \@anim at streamobj{%
-      /Type/XObject/Subtype/Form/BBox [0 0 15 15]
+    \ifcsname btn#1:#3\endcsname\else% only create if button face doesn't
+      \@anim at streamobj{%                                      % exist yet
+        /Type/XObject/Subtype/Form/BBox [0 0 15 15]
+        \ifx\empty\@anim at alpha\empty\else%
+          /Group <</S/Transparency>>%
+        \fi%
+      }{#2}%
       \ifx\empty\@anim at alpha\empty\else%
-        /Group <</S/Transparency>>%
-      \fi%
-    }{#2}%
-    \ifx\empty\@anim at alpha\empty\else%
-      \@anim at streamobj{%
-        /Type/XObject/Subtype/Form/BBox [0 0 15 15]%
-        /Resources <<%
-          /ExtGState <<%
-            /R1 <<%
-              /Type/ExtGState/ca \@anim at alpha/CA \@anim at alpha/AIS false%
+        \@anim at streamobj{%
+          /Type/XObject/Subtype/Form/BBox [0 0 15 15]%
+          /Resources <<%
+            /ExtGState <<%
+              /R1 <<%
+                /Type/ExtGState/ca \@anim at alpha/CA \@anim at alpha/AIS false%
+              >>%
             >>%
+            /XObject <</R2 \@anim at lastobj>>%
           >>%
-          /XObject <</R2 \@anim at lastobj>>%
-        >>%
-      }{/R1 gs /R2 Do}%
+        }{/R1 gs /R2 Do}%
+      \fi%
+      \@anim at newkey{btn#1:#3}{\@anim at lastobj}%
     \fi%
-    \@anim at newkey{btn#1:#3}{\@anim at lastobj}%
   }
 \fi
 
@@ -1063,7 +1280,7 @@
       }%
     \fi%
     \xdef\@anim at pathtofile{\expandafter\zap at finalspace\@filef at und\@nil}%
-  }%
+  }
 \else
   \if at anim@dvipdfmx %XeLaTeX, dvipdfmx
     \def\@anim at getpath#1#2{%
@@ -1108,36 +1325,76 @@
         }%
       \fi%
       \xdef\@anim at pathtofile{\expandafter\zap at finalspace\@filef at und\@nil}%
-    }%
-  \else %dvips
-    \def\@anim at getpath#1#2{%
-      \ifx\@empty#2\@empty%
-        \gdef\@anim at ext{.eps}% we start with `eps'
-        \IfFileExists{#1\@anim at ext}{}{%
-        \gdef\@anim at ext{.mps}%
-        \IfFileExists{#1\@anim at ext}{}{%
-        \gdef\@anim at ext{.ps}%
-        \IfFileExists{#1\@anim at ext}{}{%
-          \PackageError{animate}{%
-            None of the files\MessageBreak%
-            `#1.eps',\MessageBreak%
-            `#1.mps' or\MessageBreak%
-            `#1.ps'\MessageBreak%
-            could be found.\MessageBreak%
-            Wrong file type? Mis-spelled file name?%
-          }{}%
-        }}}%
-      \else%
-        \gdef\@anim at ext{.#2}%
-        \IfFileExists{#1\@anim at ext}{}{%
-          \PackageError{animate}{%
-            File `#1.#2' could not be found.\MessageBreak%
-            Wrong file type? Mis-spelled file name?%
-          }{}%
-        }%
-      \fi%
-      \xdef\@anim at pathtofile{\expandafter\zap at finalspace\@filef at und\@nil}%
-    }%
+    }
+  \else
+    \if at anim@dvisvgm
+      \def\@anim at getpath#1#2{%
+        \ifx\@empty#2\@empty%
+          \gdef\@anim at ext{.eps}% we start with `eps'
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.ps}%
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.svg}%
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.png}%
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.jpg}%
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.jpeg}%
+          \IfFileExists{#1\@anim at ext}{}{%
+            \PackageError{animate}{%
+              None of the files\MessageBreak%
+              `#1.eps',\MessageBreak%
+              `#1.ps',\MessageBreak%
+              `#1.svg',\MessageBreak%
+              `#1.png',\MessageBreak%
+              `#1.jpg',\MessageBreak%
+              `#1.jpeg' or\MessageBreak%
+              could be found.\MessageBreak%
+              Wrong file type? Mis-spelled file name?%
+            }{}%
+          }}}}}}%
+        \else%
+          \gdef\@anim at ext{.#2}%
+          \IfFileExists{#1\@anim at ext}{}{%
+            \PackageError{animate}{%
+              File `#1.#2' could not be found.\MessageBreak%
+              Wrong file type? Mis-spelled file name?%
+            }{}%
+          }%
+        \fi%
+        \xdef\@anim at pathtofile{\expandafter\zap at finalspace\@filef at und\@nil}%
+      }
+    \else %dvips
+      \def\@anim at getpath#1#2{%
+        \ifx\@empty#2\@empty%
+          \gdef\@anim at ext{.eps}% we start with `eps'
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.mps}%
+          \IfFileExists{#1\@anim at ext}{}{%
+          \gdef\@anim at ext{.ps}%
+          \IfFileExists{#1\@anim at ext}{}{%
+            \PackageError{animate}{%
+              None of the files\MessageBreak%
+              `#1.eps',\MessageBreak%
+              `#1.mps' or\MessageBreak%
+              `#1.ps'\MessageBreak%
+              could be found.\MessageBreak%
+              Wrong file type? Mis-spelled file name?%
+            }{}%
+          }}}%
+        \else%
+          \gdef\@anim at ext{.#2}%
+          \IfFileExists{#1\@anim at ext}{}{%
+            \PackageError{animate}{%
+              File `#1.#2' could not be found.\MessageBreak%
+              Wrong file type? Mis-spelled file name?%
+            }{}%
+          }%
+        \fi%
+        \xdef\@anim at pathtofile{\expandafter\zap at finalspace\@filef at und\@nil}%
+      }
+    \fi
   \fi
 \fi
 
@@ -1155,7 +1412,7 @@
     \offinterlineskip%
     \hbox{\raisebox{-\@anim at animdepth}{%
       \frame{%
-        \rule{0pt}{\@anim at animtotalheight}\hskip\@anim at animwidth%
+        \rule{\z@}{\@anim at animtotalheight}\hskip\@anim at animwidth%
       }%
     }}%
     \if at anim@controls%
@@ -1226,15 +1483,15 @@
       \else%
         \ifnum\@anim at first<\z@\relax\gdef\@anim at first{0}\fi%
         \ifnum\@anim at first>\@anim at lastpage\relax%
-          \xdef\@anim at first{\@anim at lastpage}%
+          \global\let\@anim at first\@anim at lastpage%
         \fi%
       \fi%
       \ifx\@anim at last\@empty%
-        \xdef\@anim at last{\@anim at lastpage}%
+        \global\let\@anim at last\@anim at lastpage%
       \else%
         \ifnum\@anim at last<\z@\relax\gdef\@anim at last{0}\fi%
         \ifnum\@anim at last>\@anim at lastpage\relax%
-          \xdef\@anim at last{\@anim at lastpage}%
+          \global\let\@anim at last\@anim at lastpage%
         \fi%
       \fi%
       \@anim at curframe=\@anim at first%
@@ -1269,15 +1526,15 @@
         \else%
           \ifnum\@anim at first<\z@\relax\gdef\@anim at first{0}\fi%
           \ifnum\@anim at first>\@anim at lastpage\relax%
-            \xdef\@anim at first{\@anim at lastpage}%
+            \global\let\@anim at first\@anim at lastpage%
           \fi%
         \fi%
         \ifx\@anim at last\@empty%
-          \xdef\@anim at last{\@anim at lastpage}%
+          \global\let\@anim at last\@anim at lastpage%
         \else%
           \ifnum\@anim at last<\z@\relax\gdef\@anim at last{0}\fi%
           \ifnum\@anim at last>\@anim at lastpage\relax%
-            \xdef\@anim at last{\@anim at lastpage}%
+            \global\let\@anim at last\@anim at lastpage%
           \fi%
         \fi%
         \@anim at curframe=\@anim at first%
@@ -1289,10 +1546,10 @@
       \fi%
     }%
   \else
-    %no multi-page support in dvips
+    %no multi-page support in dvips & dvisvgm;
     %although dvipdfmx actually has multi-page support, it lacks a way to
     %determine the total page count which is needed here
-    \def\@anim at checkmultipage#1{\setboolean{@anim at multipage}{false}}%
+    \def\@anim at checkmultipage#1#2{\setboolean{@anim at multipage}{false}}%
   \fi
 \fi
 
@@ -1338,6 +1595,14 @@
     \let\input at path\Ginput at path%
   \fi%
   \setkeys{anim at user}{#1}%
+  \xdef\@anim at btnsize{\the\dimexpr\@anim at btnsize\relax}%
+  %correct wrong option combination; totalheight overrides height
+  \ifnum\@anim at resizeflags=3\relax% height+totalheight->totalheight
+    \global\@anim at resizeflags=\@ne%
+  \fi%
+  \ifnum\@anim at resizeflags=7\relax% height+totalheight+width->totalheight+width
+    \global\@anim at resizeflags=5%
+  \fi%
   \ifthenelse{\boolean{@anim at autoplay}\OR\boolean{@anim at autoresume}}{%
     \setboolean{@anim at autoplayorresume}{true}%
   }{}%
@@ -1352,9 +1617,9 @@
     \if at anim@controls at stop\setboolean{@anim at controls}{true}\fi%
     \if at anim@controls at step\setboolean{@anim at controls}{true}\fi%
   \fi%
-  \def\@anim at base{#3}%
-  \def\@anim at first{#4}%
-  \def\@anim at last{#5}%
+  \edef\@anim at base{#3}%
+  \edef\@anim at first{#4}%
+  \edef\@anim at last{#5}%
   \@anim at checkmultipage{\@anim at base}{\@anim at ftype}%test for multipage file
   \if at anim@multipage\else% cope with wrong user input
     \ifthenelse{\equal{#4}{}\OR\equal{#5}{}}{%
@@ -1369,11 +1634,11 @@
     }{}%
   \fi%
   \def\@anim at relop{>}%
-  \edef\@anim at numtemplate{\@anim at first}%
+  \let\@anim at numtemplate\@anim at first%
   \ifnum\@anim at first>\@anim at last\relax%
     \edef\@anim at every{-\@anim at every}%
     \def\@anim at relop{<}%
-    \edef\@anim at numtemplate{\@anim at last}%
+    \let\@anim at numtemplate\@anim at last%
   \fi%
   \global\@anim at curframe=\@anim at first%
   \global\@anim at curframe@zb=\z@%
@@ -1382,6 +1647,10 @@
     \setboolean{@anim at controls}{false}%
     \setboolean{@anim at draft}{false}%
   \fi%
+  \if at anim@dvisvgm%
+    \def\@anim at method{\tw@}% using ocg-like method for dvisvgm
+    \setboolean{@anim at doscaling}{false}%
+  \fi%
   \if at anim@draft%
     \if at anim@multipage%
       %store file in a box
@@ -1395,23 +1664,14 @@
     %draw draftbox according to dimensions of the first frame
     \@anim at draftbox%
   \else%
-    \if at anim@controls%
-      %create button faces only once in the current colour combination
-      \ifcsname
-        btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape\endcsname\else%
-        \@anim at makebuttons{\the\@anim at num}%
-        \@anim at newkey{%
-          btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape}{\the\@anim at num}%
-      \fi%
-    \fi%
     \xdef\@anim at nfps{#2\space}% current frame rate
     \xdef\@anim at nfps{\expandafter\zap at space\@anim at nfps\@empty}%
-    \ifdim\@anim at nfps\p@<\z@%
+    \ifdim\@anim at nfps pt<\z@%
       \PackageError{animate}{%
         Negative frame rate `\@anim at nfps' is not allowed%
       }{}%
     \fi%
-    \xdef\@anim at fps{\@anim at nfps}%
+    \global\let\@anim at fps\@anim at nfps%
     %
     \if at anim@export\if at anim@timeline%
       \anim at export%
@@ -1450,10 +1710,12 @@
     \ifnum\@anim at poster=\@anim at mone\relax%
       \@anim at keytoaux{a\the\@anim at num.poster}{\@anim at maxframe}%
     \fi%
+    %insert animation widget & controls
     \if at anim@export\else%
-      %insert animation widget & controls
-      \@anim at insertwidgets{\the\@anim at num}{%
-        \@anim at getkeyval{btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape}}%
+      % insert <script> part
+      \if at anim@dvisvgm\@anim at script{\the\@anim at num}\fi%
+      \@anim at insertwidgets{\the\@anim at num}{\@anim at bgcolour:\@anim at fgcolour:%
+        \@anim at alpha\if at anim@dvisvgm:\@anim at btnsize\fi\@anim at lscape}%
     \fi%
   \fi%
   \@anim at endLTR%
@@ -1466,7 +1728,7 @@
 
 %inserts animation and control button widgets
 \newboolean{@anim at controls@firstgrp}
-\def\@anim at insertwidgets#1#2{%#1:@anim at num, #2 existing btn colour combination
+\def\@anim at insertwidgets#1#2{%#1:@anim at num, #2 btn colour combination
   \vtop{%
     \offinterlineskip%
     \hbox{\@anim at animwidget{#1}}%
@@ -1479,36 +1741,47 @@
         \setboolean{@anim at controls@firstgrp}{false}%
         \if at anim@controls at stop%
           \setboolean{@anim at controls@firstgrp}{true}%
+          \@anim at makebutton{EndLeft}{#2}%
           \@anim at buttonwidget{#1}{EndLeft}{EndLeft:#2}%
         \fi%
         \if at anim@controls at step%
           \setboolean{@anim at controls@firstgrp}{true}%
+          \@anim at makebutton{StepLeft}{#2}%
           \@anim at buttonwidget{#1}{StepLeft}{StepLeft:#2}%
         \fi%
         \if at anim@controls at play%
           \setboolean{@anim at controls@firstgrp}{true}%
+          \@anim at makebutton{PauseLeft}{#2}%
           \@anim at buttonwidget{#1}{PauseLeft}{PauseLeft:#2}%
+          \@anim at makebutton{PlayLeft}{#2}%
           \@anim at buttonwidget{#1}{PlayLeft}{PlayLeft:#2}%
           \@anim at buttonwidget{#1}{PlayPauseLeft}{}%
+          \@anim at makebutton{PauseRight}{#2}%
           \@anim at buttonwidget{#1}{PauseRight}{PauseRight:#2}%
+          \@anim at makebutton{PlayRight}{#2}%
           \@anim at buttonwidget{#1}{PlayRight}{PlayRight:#2}%
           \@anim at buttonwidget{#1}{PlayPauseRight}{}%
         \fi%
         \if at anim@controls at step%
           \setboolean{@anim at controls@firstgrp}{true}%
+          \@anim at makebutton{StepRight}{#2}%
           \@anim at buttonwidget{#1}{StepRight}{StepRight:#2}%
         \fi%
         \if at anim@controls at stop%
           \setboolean{@anim at controls@firstgrp}{true}%
+          \@anim at makebutton{EndRight}{#2}%
           \@anim at buttonwidget{#1}{EndRight}{EndRight:#2}%
         \fi%
         \if at anim@controls at speed%
           \if at anim@controls at firstgrp\hskip 0.3\@anim at tmpdima\fi%
           \def\@anim at tooltip{/TU (slower)}%
+          \@anim at makebutton{Minus}{#2}%
           \@anim at buttonwidget{#1}{Minus}{Minus:#2}%
           \def\@anim at tooltip{/TU (default speed)}%
+          \@anim at makebutton{Reset}{#2}%
           \@anim at buttonwidget{#1}{Reset}{Reset:#2}%
           \def\@anim at tooltip{/TU (faster)}%
+          \@anim at makebutton{Plus}{#2}%
           \@anim at buttonwidget{#1}{Plus}{Plus:#2}%
         \fi%
         \hss%
@@ -1519,6 +1792,9 @@
 
 \newcount\@anim at resizeflags% resizing flags according to options given.
 
+%post-scaling, not possible for embedded files with dvisvgm
+\newboolean{@anim at doscaling}
+
 %set animation widget dimensions
 \def\@anim at scale#1{% #1: box number
   \begingroup%
@@ -1533,13 +1809,6 @@
     \xdef\@anim at animheight{\the\dimexpr\@anim at heightarg\relax}%
     \xdef\@anim at animtotalheight{\the\dimexpr\@anim at totheightarg\relax}%
   \endgroup%
-  %correct wrong option combination; totalheight overrides height
-  \ifnum\@anim at resizeflags=3\relax% height+totalheight->totalheight
-    \global\@anim at resizeflags=\@ne%
-  \fi%
-  \ifnum\@anim at resizeflags=7\relax% height+totalheight+width->totalheight+width
-    \global\@anim at resizeflags=5%
-  \fi%
   %now resize
   \ifcase\@anim at resizeflags% bit 2^2=width, 2^1=height, 2^0=totalhight given
   \or% 1
@@ -1582,7 +1851,7 @@
     \fi%
   \fi%
   %apply scale
-  \ifdim\@anim at boxscale\p@=\@ne\p@\else%
+  \ifdim\@anim at boxscale pt=\p@\else%
     \global\setbox#1=\hbox{\scalebox{\@anim at boxscale}{\box#1}}%
   \fi%
   %dimensions after resizing
@@ -1595,136 +1864,205 @@
 %interactive Widget annotation serving as animation frame container / that is
 %overlayed on the non-interactive frame Widgets or on the page content with
 %frame OCGs
-\def\@anim at animwidget#1{%
-  \@anim at pojscript{#1}%
-  \@anim at pcjscript{#1}%
-  \@anim at otherjscript{#1}%
-  \def\@anim at annotflag{}%
-  \ifnum\@anim at poster>\@anim at maxframe\relax%
-    \PackageError{animate}{%
-      Poster frame `\@anim at poster' is out-of-bounds\MessageBreak%
-      on input line \the\inputlineno.\MessageBreak%
-      Try option `poster=last'%
-    }{}%
-  \fi%
-  \ifnum\@anim at method=\z@\relax%
-    \def\@anim at annotflag{/F 4}% 4=allow printing
-    \ifnum\@anim at poster=\@anim at mtwo\relax%
-      \ifdefined\@anim at apdummy\else% empty appearance widget
+\if at anim@dvisvgm
+  \def\@anim at animwidget#1{%
+    \ifnum\@anim at poster>\@anim at maxframe\relax%
+      \PackageError{animate}{%
+        Poster frame `\@anim at poster' is out-of-bounds\MessageBreak%
+        on input line \the\inputlineno.\MessageBreak%
+        Try option `poster=last'%
+      }{}%
+    \fi%
+    \@anim at annot{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
+      id='anm#1'
+      \if at anim@nomouse\else
+        cursor='pointer'
+        onmousedown='onMouseDownWdgt();'
+        % not working in FF while doing so in Chrome; FF fails to pass
+        % MouseEvent to handler; bug? will use addEventListener()
+        %onmouseup='onMouseUpWdgt(event);'
+      \fi%
+    }%
+    \@anim at updatebbox{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}%
+    \hbox to \@anim at animwidth {%
+      \vrule width \z@ height \@anim at animheight depth \@anim at animdepth%
+      \hss%
+    }%
+  }
+\else
+  \def\@anim at animwidget#1{%
+    \@anim at pojscript{#1}%
+    \@anim at pcjscript{#1}%
+    \def\@anim at annotflag{}%
+    \ifnum\@anim at poster>\@anim at maxframe\relax%
+      \PackageError{animate}{%
+        Poster frame `\@anim at poster' is out-of-bounds\MessageBreak%
+        on input line \the\inputlineno.\MessageBreak%
+        Try option `poster=last'%
+      }{}%
+    \fi%
+    \ifnum\@anim at method=\z@\relax%
+      \def\@anim at annotflag{/F 4}% 4=allow printing
+      \ifnum\@anim at poster=\@anim at mtwo\relax%
+        \ifdefined\@anim at apdummy\else% empty appearance widget
+          \setbox\@anim at box=\hbox{\phantom{x}}%
+          \@anim at xform{0}{0}{}{}{\@anim at box}%
+          \global\let\@anim at apdummy\@anim at lastxform%
+          \@anim at widget{1ex}{1ex}{\z@}{%
+            /Subtype/Widget%
+            /F 2%
+            /FT/Btn/Ff 65537%
+            /BS <</W 0>>%
+            /AP <</N \@anim at lastxform>>%
+            /MK <</TP 1/I \@anim at lastxform/IF<</S/A/FB true>>>>%
+            /T (0000)%
+          }%
+        \fi%
+        \def\@anim at apmk{\@anim at apdummy}%
+      \else%
+        \def\@anim at apmk{\@anim at posterap}%
+      \fi%
+    \else%
+      \ifdefined\@anim at apdummy\else% empty appearance dummy
         \setbox\@anim at box=\hbox{\phantom{x}}%
         \@anim at xform{0}{0}{}{}{\@anim at box}%
-        \xdef\@anim at apdummy{\@anim at lastxform}%
-        \@anim at pdfwid{1ex}{1ex}{\z@}{%
-          /Subtype/Widget%
-          /F 2%
-          /FT/Btn/Ff 65537%
-          /BS <</W 0>>%
-          /AP <</N \@anim at lastxform>>%
-          /MK <</TP 1/I \@anim at lastxform/IF<</S/A/FB true>>>>%
-          /T (0000)%
-        }%
+        \global\let\@anim at apdummy\@anim at lastxform%
       \fi%
       \def\@anim at apmk{\@anim at apdummy}%
-    \else%
-      \def\@anim at apmk{\@anim at posterap}%
     \fi%
-  \else%
-    \ifdefined\@anim at apdummy\else% empty appearance dummy
-      \setbox\@anim at box=\hbox{\phantom{x}}%
-      \@anim at xform{0}{0}{}{}{\@anim at box}%
-      \xdef\@anim at apdummy{\@anim at lastxform}%
-    \fi%
-    \def\@anim at apmk{\@anim at apdummy}%
-  \fi%
-  %this is for Foxit compatibility:
-  %  Widget annots don't seem to acknowledge /P* events
-  %  a non-interactive /Screen annotation for initializing the animation
-  %  upon PageOpen/PageVisible events and for clean-up upon PageClose/
-  %  PageInvisible events
-  \@anim at pdfannot{1ex}{1ex}{\z@}{%
-    /Subtype/Screen/F 2%
-    /AA <<%
-      /PV <</S/JavaScript/JS \@anim at pojscriptobj>>% PageVisible
-      /PO <</S/JavaScript/JS \@anim at pojscriptobj>>% PageOpen
-      /PI <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageInvisible
-      /PC <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageClose
-    >>%
-  }%
-  \@anim at pdfwid{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
-    /Subtype/Widget%
-    /FT/Btn/Ff \@anim at btnflag%
-    \@anim at annotflag%
-    /BS <</W 0>>%
-    /H/N%
-    /T (anm#1)%
-    /Contents (animation by animate[\@anim at version])%
-    /AA <<%
-      /PV <</S/JavaScript/JS \@anim at pojscriptobj>>% PageVisible
-      /PO <</S/JavaScript/JS \@anim at pojscriptobj>>% PageOpen
-      /PI <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageInvisible
-      /PC <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageClose
-      \@anim at otherjscriptkey%
-    >>%
-    /AP <</N \@anim at apmk>>%
-    /MK <</TP 1/I \@anim at apmk/IF<</S/A/FB true>>>>%
-  }%
-  \hbox to \@anim at animwidth {%
-    \vrule width 0pt height \@anim at animheight depth \@anim at animdepth%
-    \hss%
-  }%
-}
-
+    %this is for Foxit compatibility:
+    %  Widget annots don't seem to acknowledge /P* events
+    %  a non-interactive /Screen annotation for initializing the animation
+    %  upon PageOpen/PageVisible events and for clean-up upon PageClose/
+    %  PageInvisible events
+    \@anim at annot{1ex}{1ex}{\z@}{%
+      /Subtype/Screen/F 2%
+      /AA <<%
+        /PV <</S/JavaScript/JS \@anim at pojscriptobj>>% PageVisible
+        /PO <</S/JavaScript/JS \@anim at pojscriptobj>>% PageOpen
+        /PI <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageInvisible
+        /PC <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageClose
+      >>%
+    }%
+    \@anim at widget{\@anim at animwidth}{\@anim at animheight}{\@anim at animdepth}{%
+      /Subtype/Widget%
+      /FT/Btn/Ff \if at anim@nomouse 65537\else 65536\fi%
+      \@anim at annotflag%
+      /BS <</W 0>>%
+      /H/N%
+      /T (anm#1)%
+      /Contents (animation by animate[\@anim at version])%
+      /AA <<%
+        /PV <</S/JavaScript/JS \@anim at pojscriptobj>>% PageVisible
+        /PO <</S/JavaScript/JS \@anim at pojscriptobj>>% PageOpen
+        /PI <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageInvisible
+        /PC <</S/JavaScript/JS \@anim at pcjscriptobj>>% PageClose
+        \if at anim@nomouse\else%
+          /D <</S/JavaScript/JS (\@anim at wdgtDownJSString{#1})>>% mouse-down
+          /U <</S/JavaScript/JS (\@anim at wdgtUpJSString{#1})>>% mouse-up
+        \fi%
+      >>%
+      /AP <</N \@anim at apmk>>%
+      /MK <</TP 1/I \@anim at apmk/IF<</S/A/FB true>>>>%
+    }%
+    \hbox to \@anim at animwidth {%
+      \vrule width \z@ height \@anim at animheight depth \@anim at animdepth%
+      \hss%
+    }%
+  }
+\fi
 %creates control button widget
 \newboolean{@anim at js}
 \newboolean{@anim at mk}
-\def\@anim at buttonwidget#1#2#3{%#1:@anim at num, #2:action, #3:button face XObject
-  \def\@anim at annotflag{/F 0}% visible, but don't print
-  \def\@anim at buttonname{#2}\@anim at jstrue\@anim at mktrue%
-  \def\@anim at arg{PlayLeft}%
-  \ifx\@anim at arg\@anim at buttonname\@anim at jsfalse\fi%                          _
-  \def\@anim at arg{PauseLeft}%                             %hidden, don't print |
-  \ifx\@anim at arg\@anim at buttonname\@anim at jsfalse\def\@anim at annotflag{/F 2}\fi%_|
-  \def\@anim at arg{PlayRight}%
-  \ifx\@anim at arg\@anim at buttonname\@anim at jsfalse\fi%
-  \def\@anim at arg{PauseRight}%
-  \ifx\@anim at arg\@anim at buttonname\@anim at jsfalse\def\@anim at annotflag{/F 2}\fi%
-  \def\@anim at arg{PlayPauseLeft}%
-  \ifx\@anim at arg\@anim at buttonname\@anim at mkfalse\fi%
-  \def\@anim at arg{PlayPauseRight}%
-  \ifx\@anim at arg\@anim at buttonname\@anim at mkfalse\fi%
-  \if at anim@mk\else%
-    \ifdefined\@anim at apdummy\else% empty appearance dummy
-      \setbox\@anim at box=\hbox{\phantom{x}}%
-      \@anim at xform{0}{0}{}{}{\@anim at box}%
-      \xdef\@anim at apdummy{\@anim at lastxform}%
+\if at anim@dvisvgm
+  \def\@anim at buttonwidget#1#2#3{% #1:@anim at num, #2:action,
+                                % #3:button face and colour combination
+    \def\@anim at arg{#2}\@anim at jstrue%
+    \ifx\@anim at PlayLeft\@anim at arg%
+      \@anim at jsfalse%
+      \@anim at newocg{#1}{PlayLeft}%
     \fi%
-  \fi%
-  \if at anim@js\@anim at upjscript{#1}{#2}\fi% JavaScript actions for ButtonUp events
-  \setlength{\@anim at tmpdima}{\@anim at btnsize}%
-  \@anim at pdfwid{\@anim at tmpdima}{\@anim at tmpdima}{\z@}{%
-    /Subtype/Widget%
-    \@anim at annotflag%
-    /FT/Btn/Ff \if at anim@js 65536\else 65537\fi%
-    /H\if at anim@js/I\else/N\fi%
-    /BS <</W 0>>%
-    \if at anim@mk%
-      /AP <</N \@anim at getkeyval{btn#3}>>%
-      /MK <</TP 1/I \@anim at getkeyval{btn#3}/IF<</S/A/FB true>>>>%
-    \else%
-      /AP <</N \@anim at apdummy>>%
-      /MK <</TP 1/I \@anim at apdummy/IF<</S/A/FB true>>>>%
+    \ifx\@anim at PauseLeft\@anim at arg%
+      \@anim at jsfalse%
+      \@anim at newocg{#1}{PauseLeft}%
+      \ocgbase at add@to at off@list{\@anim at curocg}%
     \fi%
-    /T (#1.#2)%
-    \@anim at tooltip%
-    \if at anim@js/A <</S/JavaScript/JS (\@anim at upjscriptstring)>>\fi%
-  }%
-  \if at anim@js%
-    \hbox to \@anim at tmpdima {%
-      \vrule width 0pt height \@anim at tmpdima depth 0pt%
-      \hss%
+    \ifx\@anim at PlayRight\@anim at arg%
+      \@anim at jsfalse%
+      \@anim at newocg{#1}{PlayRight}%
+    \fi%
+    \ifx\@anim at PauseRight\@anim at arg%
+      \@anim at jsfalse%
+      \@anim at newocg{#1}{PauseRight}%
+      \ocgbase at add@to at off@list{\@anim at curocg}%
+    \fi%
+    % insert button face
+    \if at anim@js%
+      \ifx\@empty#3\@empty\else% PlayPauseLeft/PlayPauseRight don't have btn
+        \@anim at refxform{\@anim at getkeyval{btn#3}}%                    % faces
+      \fi%
+    \else% PlayLeft, PauseLeft, PlayRight, PauseRight
+      \ocgbase at oc@bdc{\@anim at curocg}%
+      \@anim at refxform{\@anim at getkeyval{btn#3}}%
+      \ocgbase at oc@emc%
+    \fi%
+    % insert widget
+    \if at anim@js%
+      \@anim at annot{\@anim at btnsize}{\@anim at btnsize}{\z@}{%
+        cursor='pointer' onmouseup='\@anim at btnUpJSString{#1}{\@anim at arg}'%
+      }%
+      \@anim at updatebbox{\@anim at btnsize}{\@anim at btnsize}{}%
+      \hbox to \@anim at btnsize {%
+        \vrule width \z@ height \@anim at btnsize depth \z@%
+        \hss%
+      }%
+    \fi%
+  }
+\else
+  \def\@anim at buttonwidget#1#2#3{%#1:@anim at num, #2:action,
+                                %  #3:button face and colour combination
+    \edef\@anim at arg{#2}\@anim at jstrue\@anim at mktrue%
+    \def\@anim at annotflag{/F 0}% visible, but don't print
+    \ifx\@anim at PlayLeft\@anim at arg\@anim at jsfalse\fi%       %hidden, don't print |
+    \ifx\@anim at PauseLeft\@anim at arg\@anim at jsfalse\def\@anim at annotflag{/F 2}\fi%_|
+    \ifx\@anim at PlayRight\@anim at arg\@anim at jsfalse\fi%
+    \ifx\@anim at PauseRight\@anim at arg\@anim at jsfalse\def\@anim at annotflag{/F 2}\fi%
+    \ifx\@anim at PlayPauseLeft\@anim at arg\@anim at mkfalse\fi%
+    \ifx\@anim at PlayPauseRight\@anim at arg\@anim at mkfalse\fi%
+    \if at anim@mk\else%
+      \ifdefined\@anim at apdummy\else% empty appearance dummy
+        \setbox\@anim at box=\hbox{\phantom{x}}%
+        \@anim at xform{0}{0}{}{}{\@anim at box}%
+        \global\let\@anim at apdummy\@anim at lastxform%
+      \fi%
+    \fi%
+    \@anim at widget{\@anim at btnsize}{\@anim at btnsize}{\z@}{%
+      /Subtype/Widget%
+      \@anim at annotflag%
+      /FT/Btn/Ff \if at anim@js 65536\else 65537\fi%
+      /H\if at anim@js/I\else/N\fi%
+      /BS <</W 0>>%
+      \if at anim@mk%
+        /AP <</N \@anim at getkeyval{btn#3}>>%
+        /MK <</TP 1/I \@anim at getkeyval{btn#3}/IF<</S/A/FB true>>>>%
+      \else%
+        /AP <</N \@anim at apdummy>>%
+        /MK <</TP 1/I \@anim at apdummy/IF<</S/A/FB true>>>>%
+      \fi%
+      /T (#1.#2)%
+      \@anim at tooltip%
+      \if at anim@js%
+        /A <</S/JavaScript/JS (\@anim at btnUpJSString{#1}{\@anim at arg})>>%
+      \fi%
     }%
-  \fi%
-}
+    \if at anim@js%
+      \hbox to \@anim at btnsize {%
+        \vrule width \z@ height \@anim at btnsize depth \z@%
+        \hss%
+      }%
+    \fi%
+  }
+\fi
 
 \newboolean{@anim at pauseframes} % true if \newframe* is being used
 \newboolean{@anim at chfps} % true if \newframe or \newframe* is being used
@@ -1747,6 +2085,14 @@
     \let\input at path\Ginput at path%
   \fi%
   \setkeys{anim at user}{#1}%
+  \xdef\@anim at btnsize{\the\dimexpr\@anim at btnsize\relax}%
+  %correct wrong option combination; totalheight overrides height
+  \ifnum\@anim at resizeflags=3\relax% height+totalheight->totalheight
+    \global\@anim at resizeflags=\@ne%
+  \fi%
+  \ifnum\@anim at resizeflags=7\relax% height+totalheight+width->totalheight+width
+    \global\@anim at resizeflags=5%
+  \fi%
   \ifthenelse{\boolean{@anim at autoplay}\OR\boolean{@anim at autoresume}}{%
     \setboolean{@anim at autoplayorresume}{true}%
   }{}%
@@ -1768,16 +2114,10 @@
     \setboolean{@anim at controls}{false}%
     \setboolean{@anim at draft}{false}%
   \fi%
+  \if at anim@dvisvgm%
+    \def\@anim at method{\tw@}%
+  \fi%
   \if at anim@draft\else%
-    %create button faces if necessary
-    \if at anim@controls%
-      \ifcsname
-        btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape\endcsname\else%
-        \@anim at makebuttons{\the\@anim at num}%
-        \@anim at newkey{%
-          btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape}{\the\@anim at num}%
-      \fi%
-    \fi%
     \if at anim@step\else%
       \xdef\@anim at nfps{-1}%
       \@anim at processfpsarg{#2}%
@@ -1803,8 +2143,10 @@
     \if at anim@timeline\@anim at buildtmln{\the\@anim at num}\fi%
     %insert animation widget & controls
     \if at anim@export\else%
-     \@anim at insertwidgets{\the\@anim at num}{%
-       \@anim at getkeyval{btncol:\@anim at bgcolour:\@anim at fgcolour\@anim at lscape}}%
+      % insert <script> part
+      \if at anim@dvisvgm\@anim at script{\the\@anim at num}\fi%
+      \@anim at insertwidgets{\the\@anim at num}{\@anim at bgcolour:\@anim at fgcolour:%
+        \@anim at alpha\if at anim@dvisvgm:\@anim at btnsize\fi\@anim at lscape}%
     \fi%
     % if last frame used as poster, write frame num to aux file
     \ifnum\@anim at poster=\@anim at mone\relax%
@@ -1828,24 +2170,24 @@
 }
 \def\@anim at processfpsarg#1{%
   %process frame rate argument
-  \xdef\@anim at pfps{\@anim at nfps}%
+  \global\let\@anim at pfps\@anim at nfps%
   \xdef\@anim at nfps{#1\space}%
   \xdef\@anim at nfps{\expandafter\zap at space\@anim at nfps\@empty}%
   \ifx\@anim at nfps\@empty% no change of frame rate
-    \xdef\@anim at nfps{\@anim at pfps}%
+    \global\let\@anim at nfps\@anim at pfps%
   \fi%
   \ifnum\@anim at curframe@zb=\z@\relax%
-    \xdef\@anim at fps{\@anim at nfps}% default fps
-    \xdef\@anim at nfpsat{\@anim at nfps}%
+    \global\let\@anim at fps\@anim at nfps% default fps
+    \global\let\@anim at nfpsat\@anim at nfps%
   \else%
     \xdef\@anim at nfpsat{\@anim at nfpsat,\@anim at nfps}%
   \fi%
-  \ifdim\@anim at nfps\p@=\@anim at pfps\p@\else%
+  \ifdim\@anim at nfps pt=\@anim at pfps pt\else%
     \ifnum\@anim at curframe@zb=\z@\relax\else%
       \setboolean{@anim at chfps}{true}% change fps
     \fi%
   \fi%
-  \ifdim\@anim at nfps\p@<\z@%
+  \ifdim\@anim at nfps pt<\z@%
     \PackageError{animate}{%
       Negative frame rate `\@anim at nfps' is not allowed%
     }{}%
@@ -1939,7 +2281,7 @@
     \fi%
     %now create Form XObject of box contents
     \if at anim@draft\else%
-      \@anim at xinline{#1}{#2}{\@anim at box}{!}%
+      \@anim at xinline{#1}{#2}{\@anim at box}{inline}%
     \fi%
     \if at anim@export\if at anim@timeline\else%
       \endanim at export%
@@ -2103,12 +2445,12 @@
 
 \begingroup\catcode`\_=13\let_\space
 \xdef\@anim at nusewarning{%
-  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak%
-  @_There_were_unused_animation_transparencies._____@\MessageBreak%
-  @_See_the_transcript_file_________________________@\MessageBreak%
+  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak%
+  @_There_are_unused_animation_transparencies._@\MessageBreak%
+  @_See_the_transcript_file____________________@\MessageBreak%
   @___``\jobname.log''\MessageBreak%
-  @_for_additional_information!_____________________@\MessageBreak%
-  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
+  @_for_additional_information!________________@\MessageBreak%
+  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
 }
 \endgroup
 
@@ -2172,7 +2514,7 @@
       \setboolean{@anim at eof}{false}\fi%
   }%
   \closein\@anim@@tmlnfile%
-  \xdef\@anim at transp{\@anim at frames}% total number of transparencies
+  \global\let\@anim at transp\@anim at frames% total number of transparencies
   \xdef\@anim at frames{\the\@anim at curframe@zb}%total number of actual frames
   \global\@anim at tmpcnt=\@anim at frames%
   \global\advance\@anim at tmpcnt by -\@ne%
@@ -2326,7 +2668,7 @@
   \ifx\@anim at tmp\@empty\else%
     \xdef\@anim at usrjsat{%
       \@anim at usrjsat%
-      var a\the\@anim at num_usrJSat_\the\@anim at curframe@zb=function(){#1};%
+      a\the\@anim at num_usrJS[\the\@anim at curframe@zb]=function(){#1};%
     }%
     \setboolean{@anim at usrjs}{true}%
   \fi%
@@ -2349,12 +2691,12 @@
     \@anim at getrepetitions#2\@nil%
   }%
   \ifnum\@anim at repeats=\z@\relax% =0 means: repeat until end of timeline
-    \edef\@anim at repeatuntil{\@anim at frames}%
+    \let\@anim at repeatuntil\@anim at frames%
   \else%
     \global\@anim at tmpcnt=\@anim at curframe@zb%
     \global\advance\@anim at tmpcnt by \@anim at repeats%
     \ifnum\@anim at frames<\@anim at tmpcnt\relax%
-      \edef\@anim at repeatuntil{\@anim at frames}%
+      \let\@anim at repeatuntil\@anim at frames%
     \else%
       \edef\@anim at repeatuntil{\the\@anim at tmpcnt}%
     \fi%
@@ -2457,9 +2799,9 @@
       \gdef\@anim at multlabel{}%
       \AtEndDocument{%
         \PackageWarningNoLine{animate}{%
-        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak
-        @ There were multiply-defined labels! @\MessageBreak
-        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}%
+        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak
+        @ There are multiply-defined labels! @\MessageBreak
+        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}%
       }%
     \fi%
   \fi%
@@ -2511,8 +2853,8 @@
   \global\@anim at tmpcnt=\@ne%
   \gdef\@anim at colour{}%
   \@anim at colours#1:\@nil%
-  \xdef\@anim at bgcolour{\@anim at colour}%
-  \if at anim@dvips%
+  \global\let\@anim at bgcolour\@anim at colour%
+  \ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1%
     \ifnum\@anim at tmpcnt=\@ne\relax%
       \xdef\@anim at bg{\@anim at colour\space setgray}%
     \else%
@@ -2542,8 +2884,8 @@
   \global\@anim at tmpcnt=\@ne%
   \gdef\@anim at colour{}%
   \@anim at colours#1:\@nil%
-  \xdef\@anim at fgcolour{\@anim at colour}%
-  \if at anim@dvips%
+  \global\let\@anim at fgcolour\@anim at colour%
+  \ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1%
     \ifnum\@anim at tmpcnt=\@ne\relax%
       \xdef\@anim at fg{\@anim at colour\space setgray}%
     \else%
@@ -2692,10 +3034,9 @@
     \setboolean{@anim at draft}{true}%
   }%
 }
+\setboolean{@anim at nomouse}{false}
 \define at key{anim at user}{nomouse}[true]{%
-  \ifthenelse{\equal{#1}{true}}{%
-    \gdef\@anim at btnflag{65537}%
-  }{}%
+  \setboolean{@anim at nomouse}{#1}%
 }
 \define at key{anim at user}{timeline}{%
   \IfFileExists{#1}{%
@@ -2758,7 +3099,8 @@
 %macro to reset macros and booleans
 \def\@anim at reset{%
   \gdef\@anim at label{}%
-  \xdef\@anim at boxscale{\@anim@@boxscale}%
+  \setboolean{@anim at doscaling}{true}%
+  \global\let\@anim at boxscale\@anim@@boxscale%
   \global\let\if at anim@iso=\if at anim@@iso%
   \global\@anim at resizeflags\@anim@@resizeflags%
   \global\let\@anim at widtharg\@anim@@widtharg%
@@ -2767,14 +3109,14 @@
   \let\@anim at usrwd\@anim at pkgwd%
   \let\@anim at usrht\@anim at pkght%
   \let\@anim at usrtht\@anim at pkgtht%
-  \xdef\@anim at bg{\@anim@@bg}%
-  \xdef\@anim at fg{\@anim@@fg}%
-  \xdef\@anim@@@fg{\@anim@@@@fg}%
-  \xdef\@anim at bgcolour{\@anim@@bgcolour}% default button colours
-  \xdef\@anim at fgcolour{\@anim@@fgcolour}%
+  \global\let\@anim at bg\@anim@@bg%
+  \global\let\@anim at fg\@anim@@fg%
+  \global\let\@anim@@@fg\@anim@@@@fg%
+  \global\let\@anim at bgcolour\@anim@@bgcolour% default button colours
+  \global\let\@anim at fgcolour\@anim@@fgcolour%
   \global\let\@anim at alpha\@anim@@alpha%
-  \xdef\@anim at btnsize{\@anim@@btnsize}%
-  \xdef\@anim at poster{\@anim@@poster}%
+  \global\let\@anim at btnsize\@anim@@btnsize%
+  \global\let\@anim at poster\@anim@@poster%
   \global\let\if at anim@controls=\if at anim@@controls%
   \global\let\if at anim@controls at play=\if at anim@@controls at play%
   \global\let\if at anim@controls at step=\if at anim@@controls at step%
@@ -2787,8 +3129,8 @@
   \global\let\if at anim@palindrome=\if at anim@@palindrome%
   \global\let\if at anim@step=\if at anim@@step%
   \global\let\if at anim@draft=\if at anim@@draft%
-  \xdef\@anim at method{\@anim@@method}%
-  \global\let\@anim at btnflag=\@anim@@btnflag%
+  \global\let\@anim at method\@anim@@method%
+  \global\let\if at anim@nomouse=\if at anim@@nomouse%
   \gdef\@anim at properties{}%
   \setboolean{@anim at pauseframes}{false}%
   \gdef\@anim at pauseat{}%
@@ -2806,7 +3148,7 @@
   \setboolean{@anim at multipage}{false}%
   \setboolean{@anim at meas}{false}%
   \setboolean{@anim at autoplayorresume}{false}%
-  \xdef\@anim at ftype{\@anim@@ftype}%
+  \global\let\@anim at ftype\@anim@@ftype%
 }
 
 %package options
@@ -2824,6 +3166,13 @@
     }{}%
   }%
 }%
+\define at key{anim at pkg}{dvisvgm}[]{
+  \ifthenelse{\equal{#1}{}}{}{%
+    \PackageError{animate}{%
+      Package option `dvisvgm' does not accept arguments%
+    }{}%
+  }%
+}%
 \define at key{anim at pkg}{xetex}[]{
   \ifthenelse{\equal{#1}{}}{}{%
     \PackageError{animate}{%
@@ -2844,8 +3193,8 @@
   \global\@anim at tmpcnt=\@ne%
   \gdef\@anim at colour{}%
   \@anim at colours#1:\@nil%
-  \xdef\@anim@@bgcolour{\@anim at colour}%
-  \if at anim@dvips%
+  \global\let\@anim@@bgcolour\@anim at colour%
+  \ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1%
     \ifnum\@anim at tmpcnt=\@ne\relax%
       \xdef\@anim@@bg{\@anim at colour\space setgray}%
     \else%
@@ -2871,10 +3220,12 @@
     \fi%
   \fi%
 }
-\if at anim@dvips
-  \def\@anim@@fg{0 setgray}\def\@anim@@@@fg{}%
+
+\ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1
+  %dvips .OR. dvisvgm
+  \def\@anim@@fg{0 setgray}\def\@anim@@@@fg{}
 \else% pdftex and dvipdfmx
-  \def\@anim@@fg{0 G}\def\@anim@@@@fg{0 g}%
+  \def\@anim@@fg{0 G}\def\@anim@@@@fg{0 g}
 \fi
 \def\@anim@@fgcolour{}
 \define at key{anim at pkg}{buttonfg}{%stroking colour of buttons
@@ -2881,8 +3232,8 @@
   \global\@anim at tmpcnt=\@ne%
   \gdef\@anim at colour{}%
   \@anim at colours#1:\@nil%
-  \xdef\@anim@@fgcolour{\@anim at colour}%
-  \if at anim@dvips%
+  \global\let\@anim@@fgcolour\@anim at colour%
+  \ifnum\if at anim@dvips 1\else\if at anim@dvisvgm 1\else0\fi\fi=1%
     \ifnum\@anim at tmpcnt=\@ne\relax%
       \xdef\@anim@@fg{\@anim at colour\space setgray}%
     \else%
@@ -3079,11 +3430,10 @@
     \setboolean{@anim@@draft}{true}%
   }%
 }
-\def\@anim@@btnflag{65536}%
+\newboolean{@anim@@nomouse}
+\setboolean{@anim@@nomouse}{false}
 \define at key{anim at pkg}{nomouse}[true]{%
-  \ifthenelse{\equal{#1}{true}}{%
-    \gdef\@anim@@btnflag{65537}%
-  }{}%
+  \setboolean{@anim@@nomouse}{#1}%
 }
 
 %file type (extension) of graphics files  to be embedded
@@ -3119,138 +3469,246 @@
 \edef\@anim at pkgopts{{\@ptionlist{\@currname.\@currext}}}
 \expandafter\@anim at setpkgkeys\@anim at pkgopts
 
-%JavaScript objects
-%animation widget's PageOpen/PageVisible event
-\def\@anim at pojscript#1{%
-  \@anim at streamobj{}{\@anim@@pojscript{#1}}%
-  \xdef\@anim at pojscriptobj{\@anim at lastobj}%
+%%%%%%%%%%%%%%%%%%%%%%%%
+% JavaScript part
+%%%%%%%%%%%%%%%%%%%%%%%%
+
+%some JS engine specifics
+% PDF readers
+\def\@anim at consoleshow{console.show();}
+\def\@anim at app{app.}
+\def\@anim at log{println}
+\def\@anim at shift{shift}
+\if at anim@dvisvgm
+  % web browsers
+  \def\@anim at consoleshow{}
+  \def\@anim at app{}
+  \def\@anim at log{log}
+  \def\@anim at shift{shiftKey}
+\fi
+
+\begingroup % `$' --> newline in svg output
+
+\if at anim@dvisvgm
+  %insert newline special
+  \catcode`\$=\active\gdef${{?nl}}
+\else
+  \catcode`$=\catcode`\%
+\fi
+
+%JS variable declarations
+\gdef\@anim@@jsvardecls#1{% #1: @anim at num
+  var a#1_idx;$% animation frame index
+  \ifnum\@anim at method>\z@%
+    var a#1_on;$% add. index used by Widget and OCG methods
+  \fi%
+  %takes references to frame ocgs/Field objects belonging to the current
+  %animation
+  var a#1_fr;$%
+  \ifnum\@anim at method=\z@ % icon based
+    var a#1_wid;$% reference to interactive widget
+    \ifnum\@anim at poster=\@anim at mtwo
+      var blnk;$%
+    \fi%
+  \fi%
+  \if at anim@controls at play%
+    var a#1_btnPauseLeft,a#1_btnPlayLeft,a#1_btnPauseRight,a#1_btnPlayRight;$%
+  \fi%
+  var a#1_playsRight,a#1_isPaused;$%
+  \if at anim@step\else
+    var a#1_int;$% timer id (takes return val of setIntervall())
+    % function pointers
+    var a#1_pause,a#1_playRight,a#1_playLeft,a#1_playBwd,a#1_playFwd;$%
+    \if at anim@pauseframes
+      %this array takes the frame numbers at which to pause playback
+      var a#1_pauseAt;$%
+    \fi%
+    \if at anim@chfps
+      %arrays that take frame numbers (array index) and fps values
+      var a#1_nFpsAt;$%
+    \fi
+    var a#1_fps,a#1_spd;$% frames per second (FPS), speed scaling factor
+    var a#1_setFps;$% function pointer for setting FPS
+    \if at anim@controls at speed
+      var a#1_spdIncr,a#1_spdDecr,a#1_spdReset;$% function pointers
+    \fi%
+    \if at anim@meas % speed measurement
+      var spc=String.fromCharCode(32);$%
+      var a#1_frcnt,% frame counter
+          a#1_msStart,% takes start time (in millisecs)
+          a#1_msEnd;$% takes end time (in millisecs)
+      var a#1_startMeas,a#1_stopMeas;$% function pointers
+    \fi%
+  \fi%
+  \if at anim@usrjs
+    % array of function pointers to timeline JS actions, indexed by frame number
+    var a#1_usrJS,a#1_curjs;$%
+  \fi
+  var a#1_seekFrame,a#1_stopFirst,a#1_stopLast,a#1_gotoNext,a#1_gotoPrev,%
+    a#1_stepBwd,a#1_stepFwd;$%
+  \ifx\empty\@anim at label\empty\else
+    var anim;$%
+  \fi%
 }
-\def\@anim@@pojscript#1{% #1: @anim at num
-%  console.show();%
-%  console.clear();%
-  if(typeof a#1_idx==='undefined'){% initialize animation
-    var a#1_idx\ifnum\@anim at method>\z@,a#1_on=0\fi%
-      \if at anim@step\else,a#1_int\fi;%
-    %takes references to frame ocgs/Field objects belonging to the current
-    %animation
-    var a#1_fr=new Array();%
-    %initialize fr properties
+
+%JS initialisation
+\gdef\@anim@@jsinit#1{% #1: @anim at num
+  if(!a#1_fr){$%
+    a#1_fr=new Array();$%
+    \ifnum\@anim at method>\z@%
+      a#1_on=0;$%
+    \fi%
     \ifcase\@anim at method %icon based
-      var a#1_wid=this.getField('anm#1');%reference to interactive widget
-      for(i=0;i<=\@anim at maxframe;i++){%
-        a#1_fr[i]=this.getField('#1.'+i).buttonGetIcon();%
-      }%
+      a#1_wid=this.getField('anm#1');$%reference to interactive widget
+      for(var i=0;i<=\@anim at maxframe;i++){$%
+        a#1_fr[i]=this.getField('#1.'+i).buttonGetIcon();$%
+      }$%
       \ifnum\@anim at poster=\@anim at mtwo
-        if(typeof blnk==='undefined'){% blank poster
-          var blnk=this.getField('0000').buttonGetIcon();%
-        }%
+        if(!blnk){$% blank poster (one for all animations)
+          blnk=this.getField('0000').buttonGetIcon();$%
+        }$%
       \fi%
     \or %widget based
       %get array of animation frames
-      for(i=0;i<=\@anim at maxframe;i++){%
-        a#1_fr[i]=this.getField('#1.'+i);%
-      }%
+      for(var i=0;i<=\@anim at maxframe;i++){$%
+        a#1_fr[i]=this.getField('#1.'+i);$%
+      }$%
     \or %ocg based
       %get array of ocgs of current page
-      ocg=this.getOCGs(this.pageNum);%
-      for(i in ocg){%
-        ocgName=ocg[i].name.split('.');%
-        if(ocgName[0]==#1){%
+      \if at anim@dvisvgm
+        var ocg=document.getElementsByClassName('ocg');$%
+      \else
+        var ocg=this.getOCGs(this.pageNum);$%
+      \fi
+      for(var i=0;i<ocg.length;i++){$%
+        \if at anim@dvisvgm
+          var ocgName=ocg[i].getAttribute('id').split('.');$%
+        \else
+          var ocgName=ocg[i].name.split('.');$%
+        \fi
+        if(ocgName[0]==#1){$%
           %get array of animation frames
-          a#1_fr[ocgName[1]]=ocg[i];%
+          a#1_fr[ocgName[1]]=ocg[i];$%
           %set basic frame state
-          a#1_fr[ocgName[1]].state=ocg[i].initState;%
-        }%
-      }%
+          \if at anim@dvisvgm\else
+            a#1_fr[ocgName[1]].state=ocg[i].initState;$%
+          \fi%
+        }$%
+      }$%
     \fi%
-    \if at anim@controls at play
-      var a#1_btnPauseLeft=this.getField('#1.PauseLeft');%
-      var a#1_btnPlayLeft=this.getField('#1.PlayLeft');%
-      var a#1_btnPauseRight=this.getField('#1.PauseRight');%
-      var a#1_btnPlayRight=this.getField('#1.PlayRight');%
+    \if at anim@controls at play%
+      \if at anim@dvisvgm
+        a#1_btnPauseLeft=document.getElementById('#1.PauseLeft');$%
+        a#1_btnPlayLeft=document.getElementById('#1.PlayLeft');$%
+        a#1_btnPauseRight=document.getElementById('#1.PauseRight');$%
+        a#1_btnPlayRight=document.getElementById('#1.PlayRight');$%
+      \else
+        a#1_btnPauseLeft=this.getField('#1.PauseLeft');$%
+        a#1_btnPlayLeft=this.getField('#1.PlayLeft');$%
+        a#1_btnPauseRight=this.getField('#1.PauseRight');$%
+        a#1_btnPlayRight=this.getField('#1.PlayRight');$%
+      \fi%
     \fi%
     %playing state and direction
     \if at anim@step%
-      \if at anim@palindrome var a#1_playsRight=true;\fi%
+      \if at anim@palindrome
+        a#1_playsRight=true;$%
+      \fi%
     \else
-      a#1_playsRight=true;%
+      a#1_playsRight=true;$%
     \fi
-    var a#1_isPaused=false;%
+    a#1_isPaused=false;$%
     \if at anim@step\else
-      var a#1_playing=false;%
+      a#1_playing=false;$%
       \if at anim@pauseframes
-        %this array takes the frame numbers at which to pause playback
-        var a#1_pauseAt=new Array();%
+        a#1_pauseAt=new Array();$% frame numbers at which to pause playback
         \@anim at pauseat%
       \fi%
       \if at anim@chfps
         %arrays that take frame numbers (array index) and fps values
-        var a#1_nFpsAt=new Array(\@anim at nfpsat);%
+        a#1_nFpsAt=new Array(\@anim at nfpsat);$%
       \fi
-      var a#1_fps=\@anim at fps==0?1e-6:\@anim at fps;%
-      var a#1_spd=1;%
-      var a#1_setFps=function(f){%
-        a#1_fps=f==0?1e-6:f;%
-        if(a#1_playing){%
-          if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}%
-        }%
-      };%
+      \ifdim\@anim at fps pt=\z@%
+        a#1_fps=1e-6;$%
+      \else
+        a#1_fps=\@anim at fps;$%
+      \fi
+      a#1_spd=1;$%
+      a#1_setFps=function(f){$%
+        a#1_fps=(f==0?1e-6:f);$%
+        if(a#1_playing){$%
+          if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$%
+        }$%
+      };$%
     \fi%
     \if at anim@usrjs
       %array to take frame numbers (array index) and user provided JavaScript
-      \@anim at usrjsat%
+      a#1_usrJS=new Array();$%
+      \@anim at usrjsat% populate array
     \fi%
     %actions
-    var a#1_seekFrame=function(f){%
+    a#1_seekFrame=function(f){$%
       \ifnum\@anim at poster=\@anim at mtwo
-        if(f<-1){%
+        if(f<-1){$%
           \ifcase\@anim at method %icon based
-            a#1_wid.buttonSetIcon(blnk);%
-            this.dirty=false;%
+            a#1_wid.buttonSetIcon(blnk);$%
+            this.dirty=false;$%
           \or %widget based
-            a#1_on=0;%
-            a#1_fr[0].display=display.hidden;%
-            this.dirty=false;%
+            a#1_on=0;$%
+            a#1_fr[0].display=display.hidden;$%
+            this.dirty=false;$%
           \or %ocg based
-            a#1_on=0;%
-            a#1_fr[0].state=false;%
+            a#1_on=0;$%
+            \if at anim@dvisvgm
+              a#1_fr[0].setAttribute('visibility','hidden');$%
+            \else
+              a#1_fr[0].state=false;$%
+            \fi%
           \fi
-          a#1_idx=-1;%
-        }%
+          a#1_idx=-1;$%
+        }$%
       \fi
-      if(f>\@anim at maxframe||f<0){return -1;}%
-      a#1_idx=f;%
+      if(f>\@anim at maxframe||f<0){return -1;}$%
+      a#1_idx=f;$%
       \if at anim@usrjs
-        if(typeof this['a#1_usrJSat_'+f]!=='undefined'){%
-          ret=app.setTimeOut(% execute JS in "parallel"
-            'try{a#1_usrJSat_'+f+'();}catch(e){console.println(e);}',1%
-          );%
-        }%
+        if(typeof a#1_usrJS[f]!=='undefined'){$%
+          a#1_curjs=a#1_usrJS[f];$%
+          var ret=\@anim at app setTimeOut(% execute JS in "parallel"
+            'try{a#1_curjs();}catch(e){console.\@anim at log(e);}',1%
+          );$%
+        }$%
       \fi%
       \ifcase\@anim at method %icon based
-        a#1_wid.buttonSetIcon(a#1_fr[f]);%
-        this.dirty=false;%
+        a#1_wid.buttonSetIcon(a#1_fr[f]);$%
+        this.dirty=false;$%
       \or %widget based
-        a#1_fr[a#1_on].display=display.hidden;%
-        a#1_fr[f].display=display.visible;%
-        a#1_on=f;%
-        this.dirty=false;%
-      \or %ocg based
-        a#1_fr[a#1_on].state=false;%
-        a#1_fr[f].state=true;%
-        a#1_on=f;%
-      \fi
+        a#1_fr[a#1_on].display=display.hidden;$%
+        a#1_fr[f].display=display.visible;$%
+        a#1_on=f;$%
+        this.dirty=false;$%
+      \or%ocg based
+        \if at anim@dvisvgm
+          a#1_fr[a#1_on].setAttribute('visibility','hidden');$%
+          a#1_fr[f].setAttribute('visibility','visible');$%
+        \else
+          a#1_fr[a#1_on].state=false;$%
+          a#1_fr[f].state=true;$%
+        \fi
+        a#1_on=f;$%
+      \fi%
       \if at anim@step\else%
         \if at anim@chfps
           if(a#1_nFpsAt[f]!=a#1_fps){%
             a#1_setFps(a#1_nFpsAt[f]);%
-          }%
+          }$%
         \fi%
-        \if at anim@meas a#1_frcnt++;\fi%
+        \if at anim@meas
+          a#1_frcnt++;$%
+        \fi%
       \fi%
-      return 0;%
-    };%
-    var a#1_stopFirst=function(){%
+      return 0;$%
+    };$%
+    a#1_stopFirst=function(){%
       \if at anim@step
         a#1_isPaused=false;% stop
       \else
@@ -3257,8 +3715,8 @@
         a#1_pause(true);% stop
       \fi
       a#1_seekFrame(0);%
-    };%
-    var a#1_stopLast=function(){%
+    };$%
+    a#1_stopLast=function(){%
       \if at anim@step
         a#1_isPaused=false;% stop
       \else
@@ -3265,268 +3723,311 @@
         a#1_pause(true);% stop
       \fi
       a#1_seekFrame(\@anim at maxframe);%
-    };%
-    var a#1_gotoNext=function(){%
-      if(a#1_seekFrame(a#1_idx+1)<0){%
-        \if at anim@step\else\if at anim@meas a#1_stopMeas();\fi\fi%
+    };$%
+    a#1_gotoNext=function(){$%
+      if(a#1_seekFrame(a#1_idx+1)<0){$%
+        \if at anim@step\else\if at anim@meas
+          a#1_stopMeas();$%
+        \fi\fi%
         \if at anim@palindrome%
           \if at anim@step
-            a#1_stopLast();%
-            a#1_playsRight=false;%
+            a#1_stopLast();$%
+            a#1_playsRight=false;$%
           \else
             if(a#1_playing){%
               a#1_seekFrame(a#1_idx-1);%
               a#1_playLeft();%
-            }%
+            }$%
           \fi%
         \else%
           \if at anim@step
-            a#1_stopLast();%
+            a#1_stopLast();$%
           \else%
             \if at anim@loop
               if(a#1_playing){%
                 a#1_seekFrame(0);%
                 a#1_setFps(\@anim at fps);%
-              }else{a#1_stopLast();}%
+              }else{a#1_stopLast();}$%
             \else
-              a#1_stopLast();%
+              a#1_stopLast();$%
             \fi%
           \fi%
         \fi
-        return;%
-      }%
+        return;$%
+      }$%
       \if at anim@step\else%
         \if at anim@pauseframes
-          if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}%
+          if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}$%
         \fi%
       \fi%
-    };%
-    var a#1_gotoPrev=function(){%
-      if(a#1_seekFrame(a#1_idx-1)<0){%
-        \if at anim@step\else\if at anim@meas a#1_stopMeas();\fi\fi%
+    };$%
+    a#1_gotoPrev=function(){$%
+      if(a#1_seekFrame(a#1_idx-1)<0){$%
+        \if at anim@step\else\if at anim@meas
+          a#1_stopMeas();$%
+        \fi\fi%
         \if at anim@palindrome%
           \if at anim@step
-            a#1_stopFirst();%
-            a#1_playsRight=true;%
+            a#1_stopFirst();$%
+            a#1_playsRight=true;$%
           \else
             if(a#1_playing){%
               a#1_seekFrame(a#1_idx+1);%
               a#1_playRight();%
-            }%
+            }$%
           \fi%
         \else%
           \if at anim@step
-            a#1_stopFirst();%
+            a#1_stopFirst();$%
           \else%
             \if at anim@loop
               if(a#1_playing){%
                 a#1_seekFrame(\@anim at maxframe);%
-              }else{a#1_stopFirst();}%
+              }else{a#1_stopFirst();}$%
             \else
-              a#1_stopFirst();%
+              a#1_stopFirst();$%
             \fi%
           \fi%
         \fi
-        return;%
-      }%
+        return;$%
+      }$%
       \if at anim@step\else%
         \if at anim@pauseframes
-          if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}%
+          if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}$%
         \fi%
       \fi%
-    };%
+    };$%
     \if at anim@step\else
-      var a#1_pause=function(stop){%
-        try{app.clearInterval(a#1_int);}catch(e){}%
-        a#1_playing=false;%
-        a#1_isPaused=!stop;%
+      a#1_pause=function(stop){$%
+        try{\@anim at app clearInterval(a#1_int);}catch(e){}$%
+        a#1_playing=false;$%
+        a#1_isPaused=!stop;$%
         \if at anim@controls at play
-          a#1_btnPauseLeft.display=display.hidden;%
-          a#1_btnPlayLeft.display=display.visible;%
-          a#1_btnPauseRight.display=display.hidden;%
-          a#1_btnPlayRight.display=display.visible;%
-          this.dirty=false;%
+          \if at anim@dvisvgm
+            a#1_btnPauseLeft.setAttribute('visibility','hidden');$%
+            a#1_btnPlayLeft.setAttribute('visibility','visible');$%
+            a#1_btnPauseRight.setAttribute('visibility','hidden');$%
+            a#1_btnPlayRight.setAttribute('visibility','visible');$%
+          \else
+            a#1_btnPauseLeft.display=display.hidden;$%
+            a#1_btnPlayLeft.display=display.visible;$%
+            a#1_btnPauseRight.display=display.hidden;$%
+            a#1_btnPlayRight.display=display.visible;$%
+            this.dirty=false;$%
+          \fi%
         \fi%
-      };%
-      var a#1_playRight=function(){%
+      };$%
+      a#1_playRight=function(){$%
         \if at anim@meas a#1_startMeas();\fi
-        try{tmp_int=app.setInterval('a#1_gotoNext()',%
-          1000/a#1_fps/a#1_spd);}catch(e){}%
-        try{app.clearInterval(a#1_int);}catch(e){}%
-        a#1_int=tmp_int;%
-        a#1_playsRight=true;%
-        a#1_playing=true;%
-        a#1_isPaused=false;%
-        \if at anim@controls at play
-          a#1_btnPauseLeft.display=display.visible;%
-          a#1_btnPlayLeft.display=display.hidden;%
-          a#1_btnPauseRight.display=display.visible;%
-          a#1_btnPlayRight.display=display.hidden;%
-          this.dirty=false;%
+        var tmp_int;$%
+        try{tmp_int=\@anim at app setInterval('a#1_gotoNext()',%
+          1000/a#1_fps/a#1_spd);}catch(e){}$%
+        try{\@anim at app clearInterval(a#1_int);}catch(e){}$%
+        a#1_int=tmp_int;$%
+        a#1_playsRight=true;$%
+        a#1_playing=true;$%
+        a#1_isPaused=false;$%
+        \if at anim@controls at play%
+          \if at anim@dvisvgm
+            a#1_btnPauseLeft.setAttribute('visibility','visible');$%
+            a#1_btnPlayLeft.setAttribute('visibility','hidden');$%
+            a#1_btnPauseRight.setAttribute('visibility','visible');$%
+            a#1_btnPlayRight.setAttribute('visibility','hidden');$%
+          \else
+            a#1_btnPauseLeft.display=display.visible;$%
+            a#1_btnPlayLeft.display=display.hidden;$%
+            a#1_btnPauseRight.display=display.visible;$%
+            a#1_btnPlayRight.display=display.hidden;$%
+            this.dirty=false;$%
+          \fi%
         \fi%
-      };%
-      var a#1_playLeft=function(){%
+      };$%
+      a#1_playLeft=function(){$%
         \if at anim@meas a#1_startMeas();\fi
-        try{tmp_int=app.setInterval('a#1_gotoPrev()',%
-          1000/a#1_fps/a#1_spd);}catch(e){}%
-        try{app.clearInterval(a#1_int);}catch(e){}%
-        a#1_int=tmp_int;%
-        a#1_playsRight=false;%
-        a#1_playing=true;%
-        a#1_isPaused=false;%
-        \if at anim@controls at play
-          a#1_btnPauseLeft.display=display.visible;%
-          a#1_btnPlayLeft.display=display.hidden;%
-          a#1_btnPauseRight.display=display.visible;%
-          a#1_btnPlayRight.display=display.hidden;%
-          this.dirty=false;%
+        var tmp_int;$%
+        try{tmp_int=\@anim at app setInterval('a#1_gotoPrev()',%
+          1000/a#1_fps/a#1_spd);}catch(e){}$%
+        try{\@anim at app clearInterval(a#1_int);}catch(e){}$%
+        a#1_int=tmp_int;$%
+        a#1_playsRight=false;$%
+        a#1_playing=true;$%
+        a#1_isPaused=false;$%
+        \if at anim@controls at play%
+          \if at anim@dvisvgm
+            a#1_btnPauseLeft.setAttribute('visibility','visible');$%
+            a#1_btnPlayLeft.setAttribute('visibility','hidden');$%
+            a#1_btnPauseRight.setAttribute('visibility','visible');$%
+            a#1_btnPlayRight.setAttribute('visibility','hidden');$%
+          \else
+            a#1_btnPauseLeft.display=display.visible;$%
+            a#1_btnPlayLeft.display=display.hidden;$%
+            a#1_btnPauseRight.display=display.visible;$%
+            a#1_btnPlayRight.display=display.hidden;$%
+            this.dirty=false;$%
+          \fi%
         \fi%
-      };%
+      };$%
       \if at anim@controls at speed
-        var a#1_spdIncr=function(){% speed up animation
+        a#1_spdIncr=function(){% speed up animation
           a#1_spd*=1.1;%
           a#1_setFps(a#1_fps);%
-        };%
-        var a#1_spdDecr=function(){% slow down animation
+        };$%
+        a#1_spdDecr=function(){% slow down animation
           a#1_spd/=1.1;%
           a#1_setFps(a#1_fps);%
-        };%
-        var a#1_spdReset=function(){% reset to default speed
+        };$%
+        a#1_spdReset=function(){% reset to default speed
           a#1_spd=1;%
           a#1_setFps(a#1_fps);%
-        };%
+        };$%
       \fi%
       \if at anim@meas
-        spc=String.fromCharCode(32);%
-        var a#1_frcnt,% frame counter for speed measurements
-            a#1_msStart,% takes start time (in millisecs)
-            a#1_msEnd;% takes end time (in millisecs)
-        var a#1_startMeas=function(){%
+        a#1_startMeas=function(){%
           a#1_frcnt=1;% reset frame counter
           a#1_msStart=(new Date()).getTime();%
-        };%
-        var a#1_stopMeas=function(){%
-          a#1_msEnd=(new Date()).getTime();%
-          console.show();console.println(%
+        };$%
+        a#1_stopMeas=function(){$%
+          a#1_msEnd=(new Date()).getTime();$%
+          \@anim at consoleshow console.\@anim at log(%
             'av.'+spc+'frame'+spc+'rate:'+spc+%
             1e3*a#1_frcnt/(a#1_msEnd-a#1_msStart)+spc+'fps'%
-          );%
-        };%
+          );$%
+        };$%
       \fi%
     \fi%
     \if at anim@step
-      var a#1_stepBwd=function(){%
+      a#1_stepBwd=function(){%
         a#1_seekFrame(a#1_idx-1);%
         a#1_isPaused=true;%
-      };%
-      var a#1_stepFwd=function(){%
+      };$%
+      a#1_stepFwd=function(){%
         a#1_seekFrame(a#1_idx+1);%
         a#1_isPaused=true;%
-      };%
+      };$%
     \else
-      var a#1_stepBwd=function(){if(!a#1_playing){%
+      a#1_stepBwd=function(){if(!a#1_playing){%
         a#1_seekFrame(a#1_idx-1);%
         a#1_isPaused=true;%
-      }};%
-      var a#1_stepFwd=function(){if(!a#1_playing){%
+      }};$%
+      a#1_stepFwd=function(){if(!a#1_playing){%
         a#1_seekFrame(a#1_idx+1);%
         a#1_isPaused=true;%
-      }};%
-      var a#1_playBwd=function(){%
+      }};$%
+      a#1_playBwd=function(){%
         if(a#1_idx==0||!a#1_isPaused){a#1_stopLast();}%
         a#1_playLeft();%
-      };%
-      var a#1_playFwd=function(){%
+      };$%
+      a#1_playFwd=function(){%
         if(a#1_idx==\@anim at maxframe||!a#1_isPaused){a#1_stopFirst();}%
         a#1_playRight();%
-      };%
+      };$%
     \fi%
     %animation API for labelled anims
     \ifx\empty\@anim at label\empty\else
-      if(typeof anim==='undefined'){var anim=new Array();}%
-      if(typeof anim['\@anim at label']==='undefined'){%
-        anim['\@anim at label']={%
+      if(!anim){anim=new Array();}$%
+      if(typeof anim['\@anim at label']==='undefined'){$%
+        anim['\@anim at label']={$%
           \if at anim@step\else
-            playBwd:a#1_playBwd,%
-            playFwd:a#1_playFwd,%
-            pause:a#1_pause,%
-            get isPlaying(){return a#1_playing;},%
-            get fps(){return a#1_fps;},%
-            set fps(f){%
+            playBwd:a#1_playBwd,$%
+            playFwd:a#1_playFwd,$%
+            pause:a#1_pause,$%
+            get isPlaying(){return a#1_playing;},$%
+            get fps(){return a#1_fps;},$%
+            set fps(f){$%
               if(f<0||isNaN(f)){%
                 throw new RangeError('Frame_rate_not_in_allowed_range');%
               }else{a#1_setFps(f);}%
-            },%
-            get speed(){return a#1_spd;},%
-            set speed(s){%
-              if(s<=0||isNaN(s)){%
-                throw new RangeError('Speed_factor_not_in_allowed_range');%
-              }else{%
-                a#1_spd=s;%
-                a#1_setFps(a#1_fps);%
-              }%
-            },%
-            get dt(){return 1000/a#1_fps/a#1_spd;},%
-            get playsFwd(){return a#1_playsRight;},%
+            },$%
+            get speed(){return a#1_spd;},$%
+            set speed(s){$%
+              if(s<=0||isNaN(s)){$%
+                throw new RangeError('Speed_factor_not_in_allowed_range');$%
+              }else{$%
+                a#1_spd=s;$%
+                a#1_setFps(a#1_fps);$%
+              }$%
+            },$%
+            get dt(){return 1000/a#1_fps/a#1_spd;},$%
+            get playsFwd(){return a#1_playsRight;},$%
           \fi
-          get numFrames(){return \@anim at frames;},%
-          get frameNum(){return a#1_idx;},%
-          set frameNum(f){%
-            f=Math.floor(f);%
+          get numFrames(){return \@anim at frames;},$%
+          get frameNum(){return a#1_idx;},$%
+          set frameNum(ff){$%
+            var f=Math.floor(ff);$%
             if(f<0||f>\@anim at maxframe||isNaN(f)){%
               throw new RangeError('Frame_number_not_in_allowed_range');%
-            }%
+            }$%
             \if at anim@step
-              if(a#1_seekFrame(f)>-1)a#1_isPaused=true;%
+              if(a#1_seekFrame(f)>-1)a#1_isPaused=true;$%
             \else
-              if(a#1_playing){%
-                a#1_pause();a#1_seekFrame(f);%
-                if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}%
-              }else{if(a#1_seekFrame(f)>-1)a#1_isPaused=true;}%
+              if(a#1_playing){$%
+                a#1_pause();a#1_seekFrame(f);$%
+                if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$%
+              }else{if(a#1_seekFrame(f)>-1)a#1_isPaused=true;}$%
             \fi%
-          },%
-          stopFirst:a#1_stopFirst,%
-          stopLast:a#1_stopLast%
-        };%
-      }%
+          },$%
+          stopFirst:a#1_stopFirst,$%
+          stopLast:a#1_stopLast$%
+        };$%
+      }$%
     \fi%
     %poster=none
-    \ifnum\@anim at poster=\@anim at mtwo a#1_seekFrame(-2);\fi%
+    \ifnum\@anim at poster=\@anim at mtwo
+      a#1_seekFrame(-2);$%
+    \fi%
     %poster=<num>|first
-    \ifnum\@anim at poster>\@anim at mone a#1_seekFrame(\@anim at poster);\fi%
+    \ifnum\@anim at poster>\@anim at mone
+      a#1_seekFrame(\@anim at poster);$%
+    \fi%
     %poster=last
-    \ifnum\@anim at poster=\@anim at mone a#1_seekFrame(\@anim at maxframe);\fi%
+    \ifnum\@anim at poster=\@anim at mone
+      a#1_seekFrame(\@anim at maxframe);$%
+    \fi%
   }%
+}
+
+%page-open/visible code
+\gdef\@anim@@pojscript#1{% #1: @anim at num
   \if at anim@step\else%
     \if at anim@autoplayorresume%
       \if at anim@autoresume
-        if(a#1_isPaused){%
+        if(a#1_isPaused){$%
       \fi
-        if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}%
+        if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$%
       \if at anim@autoresume%
-        }%
+        }$%
       \fi%
     \fi%
   \fi%
 }
 
-%animation widget's PageClose and PageInvisible events
-\def\@anim at pcjscript#1{%
-  \@anim at streamobj{}{\@anim@@pcjscript{#1}}%
-  \xdef\@anim at pcjscriptobj{\@anim at lastobj}%
+%animation PDF widget's PageOpen/PageVisible code as PDF stream object
+\gdef\@anim at pojscript#1{% @anim at num
+  \@anim at streamobj{}{%
+%    \@anim at consoleshow%
+%    console.clear();%
+    \@anim@@jsvardecls{#1}%
+    \@anim@@jsinit{#1}%
+    \@anim@@pojscript{#1}%
+  }%
+  \global\let\@anim at pojscriptobj\@anim at lastobj%
 }
-\def\@anim@@pcjscript#1{% #1: @anim at num
+
+%page-close/invisible code
+\gdef\@anim@@pcjscript#1{% #1: @anim at num
   \if at anim@step%
-    \if at anim@palindrome a#1_playsRight=true;\fi%
+    \if at anim@palindrome
+      a#1_playsRight=true;$%
+    \fi%
   \else
-    if(a#1_playing){
+    if(a#1_playing){%
       \if at anim@autopause
         a#1_pause();%
       \else
         a#1_pause(true);% stop
       \fi%
-    }
-    if(!a#1_isPaused)a#1_playsRight=true;%
+    }$%
+    if(!a#1_isPaused)a#1_playsRight=true;$%
   \fi
   %re-display poster frame
   if(!a#1_isPaused){% i.e. if stopped
@@ -3536,110 +4037,165 @@
     \ifnum\@anim at poster>\@anim at mone a#1_seekFrame(\@anim at poster);\fi%
     %poster=last
     \ifnum\@anim at poster=\@anim at mone a#1_seekFrame(\@anim at maxframe);\fi%
-  }%
+  }$%
 }
 
+%animation PDF widget's PageClose and PageInvisible code as PDF stream object
+\gdef\@anim at pcjscript#1{%
+  \@anim at streamobj{}{\@anim@@pcjscript{#1}}%
+  \global\let\@anim at pcjscriptobj\@anim at lastobj%
+}
+
 %other trigger events in the anim widget's AA dictionary
-\def\@anim at otherjscript#1{%
-  \xdef\@anim at otherjscriptkey{%
-    /D <</S/JavaScript/JS (%
-      app.focusRect=false;% disable focus rectangle
-      \if at anim@step\else % pause on MouseDown
-        try{if(a#1_playing){a#1_pause();}}catch(e){}%
-      \fi%
-    )>>%
-    /U <</S/JavaScript/JS (% play/resume on MouseUp
-      try{%
-        \if at anim@step%
-          \if at anim@palindrome
-            if(event.shift)a#1_playsRight=!a#1_playsRight;%
-            if(a#1_idx==\@anim at maxframe){%
-              a#1_playsRight=false;%
-            }else if(a#1_idx==0){%
-              a#1_playsRight=true;%
-            }%
-            if(a#1_playsRight){%
-              a#1_gotoNext();%
-            }else{%
-              a#1_gotoPrev();%
-            }%
-          \else
-            if(event.shift){%
-              if(a#1_idx==0){%
-                a#1_stopLast();%
-              }else{%
-                a#1_gotoPrev();%
-              }%
-            }else{%
-              if(a#1_idx==\@anim at maxframe){%
-                a#1_stopFirst();%
-              }else{%
-                a#1_gotoNext();%
-              }%
-            }%
-          \fi
-          a#1_isPaused=true;%
-        \else
-          if(!a#1_isPaused)a#1_stopFirst();%
-          if(event.shift)a#1_playsRight=!a#1_playsRight;%
-          \if at anim@palindrome
-            if(a#1_idx==0)a#1_playsRight=true;%
-            if(a#1_idx==\@anim at maxframe)a#1_playsRight=false;%
-          \else
-            if(a#1_idx==\@anim at maxframe&&a#1_playsRight)a#1_stopFirst();%
-            if(a#1_idx==0&&!a#1_playsRight)a#1_stopLast();%
-          \fi
-          if(a#1_playsRight){%
-            a#1_playRight();%
+\gdef\@anim at wdgtDownJSString#1{%
+  \if at anim@dvisvgm\else
+    app.focusRect=false;$% disable focus rectangle
+  \fi%
+  \if at anim@step\else % pause on MouseDown
+    try{if(a#1_playing){a#1_pause();}}catch(e){}$%
+  \fi%
+}%
+\gdef\@anim at wdgtUpJSString#1{%
+  try{$%
+    \if at anim@step%
+      \if at anim@palindrome
+        if(event.\@anim at shift)a#1_playsRight=!a#1_playsRight;$%
+        if(a#1_idx==\@anim at maxframe){%
+          a#1_playsRight=false;%
+        }else if(a#1_idx==0){%
+          a#1_playsRight=true;%
+        }$%
+        if(a#1_playsRight){%
+          a#1_gotoNext();%
+        }else{%
+          a#1_gotoPrev();%
+        }$%
+      \else
+        if(event.\@anim at shift){%
+          if(a#1_idx==0){%
+            a#1_stopLast();%
           }else{%
-            a#1_playLeft();%
-          }%
-        \fi%
-      }catch(e){}%
-    )>>%
-  }%
-}
+            a#1_gotoPrev();%
+          }$%
+        }else{%
+          if(a#1_idx==\@anim at maxframe){%
+            a#1_stopFirst();%
+          }else{%
+            a#1_gotoNext();%
+          }$%
+        }%
+      \fi
+      a#1_isPaused=true;$%
+    \else
+      if(!a#1_isPaused)a#1_stopFirst();$%
+      if(event.\@anim at shift)a#1_playsRight=!a#1_playsRight;$%
+      \if at anim@palindrome
+        if(a#1_idx==0)a#1_playsRight=true;$%
+        if(a#1_idx==\@anim at maxframe)a#1_playsRight=false;$%
+      \else
+        if(a#1_idx==\@anim at maxframe&&a#1_playsRight)a#1_stopFirst();$%
+        if(a#1_idx==0&&!a#1_playsRight)a#1_stopLast();$%
+      \fi
+      if(a#1_playsRight){%
+        a#1_playRight();%
+      }else{%
+        a#1_playLeft();%
+      }$%
+    \fi%
+  }catch(e){}$%
+}%
 
+\gdef\@anim at EndLeft{EndLeft}%
+\gdef\@anim at StepLeft{StepLeft}%
+\gdef\@anim at PlayPauseLeft{PlayPauseLeft}%
+\gdef\@anim at PlayLeft{PlayLeft}%
+\gdef\@anim at PauseLeft{PauseLeft}%
+\gdef\@anim at PlayPauseRight{PlayPauseRight}%
+\gdef\@anim at PlayRight{PlayRight}%
+\gdef\@anim at PauseRight{PauseRight}%
+\gdef\@anim at StepRight{StepRight}%
+\gdef\@anim at EndRight{EndRight}%
+\gdef\@anim at Minus{Minus}%
+\gdef\@anim at Reset{Reset}%
+\gdef\@anim at Plus{Plus}%
+
 %actions for control buttons
-\def\@anim at upjscript#1#2{%
-  \def\@anim at action{#2}%
-  \def\@anim at EndLeft{EndLeft}%
-  \def\@anim at StepLeft{StepLeft}%
-  \def\@anim at PlayPauseLeft{PlayPauseLeft}%
-  \def\@anim at PlayPauseRight{PlayPauseRight}%
-  \def\@anim at StepRight{StepRight}%
-  \def\@anim at EndRight{EndRight}%
-  \def\@anim at Minus{Minus}%
-  \def\@anim at Reset{Reset}%
-  \def\@anim at Plus{Plus}%
-  \xdef\@anim at upjscriptstring{%
+\gdef\@anim at btnUpJSString#1#2{%
+  \if at anim@dvisvgm\else
     app.focusRect=false;%
-    \ifx\@anim at action\@anim at EndLeft
-      a#1_stopFirst();%
-    \else%
-    \ifx\@anim at action\@anim at StepLeft
-      a#1_stepBwd();%
-    \else%
-    \ifx\@anim at action\@anim at PlayPauseLeft
-      if(a#1_playing){a#1_pause();}else{a#1_playBwd();}%
-    \else%
-    \ifx\@anim at action\@anim at PlayPauseRight
-      if(a#1_playing){a#1_pause();}else{a#1_playFwd();}%
-    \else%
-    \ifx\@anim at action\@anim at StepRight
-      a#1_stepFwd();%
-    \else%
-    \ifx\@anim at action\@anim at EndRight
-      a#1_stopLast();%
-    \else%
-    \ifx\@anim at action\@anim at Minus
-      a#1_spdDecr();%
-    \else%
-    \ifx\@anim at action\@anim at Reset
-      a#1_spdReset();%
-    \else%
-    \ifx\@anim at action\@anim at Plus
-      a#1_spdIncr();%
-    \fi\fi\fi\fi\fi\fi\fi\fi\fi%
-  }%
+  \fi%
+  \ifx#2\@anim at EndLeft
+    a#1_stopFirst();%
+  \else%
+  \ifx#2\@anim at StepLeft
+    a#1_stepBwd();%
+  \else%
+  \ifx#2\@anim at PlayPauseLeft
+    if(a#1_playing){a#1_pause();}else{a#1_playBwd();}%
+  \else%
+  \ifx#2\@anim at PlayPauseRight
+    if(a#1_playing){a#1_pause();}else{a#1_playFwd();}%
+  \else%
+  \ifx#2\@anim at StepRight
+    a#1_stepFwd();%
+  \else%
+  \ifx#2\@anim at EndRight
+    a#1_stopLast();%
+  \else%
+  \ifx#2\@anim at Minus
+    a#1_spdDecr();%
+  \else%
+  \ifx#2\@anim at Reset
+    a#1_spdReset();%
+  \else%
+  \ifx#2\@anim at Plus
+    a#1_spdIncr();%
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi%
 }
+
+\if at anim@dvisvgm
+  \gdef\@anim at script#1{% #1: anim num
+    \special{dvisvgm:raw
+      $<defs>$%
+      <script type="text/javascript">$%
+      <![CDATA[$%
+        \@anim@@jsvardecls{#1}%
+        function onload(){$%
+          \@anim@@jsinit{#1}%
+          \if at anim@nomouse\else
+            document.getElementById('anm#1').addEventListener('mouseup',%
+              onMouseUpWdgt);$%
+          \fi%
+          onvisible();$% in case of `autoplay' option
+        }$%
+        function onvisible(){$%
+          \@anim@@pojscript{#1}%
+        }$%
+        function onhidden(){$%
+          \@anim@@pcjscript{#1}%
+        }$%
+        function onVisibilityChange(){$%
+          if(document.hidden){%
+            try{onhidden();}catch(e){}%
+          }else{%
+            try{onvisible();}catch(e){}%
+          }$%
+        }$%
+	      document.addEventListener('visibilitychange',onVisibilityChange);$%
+	      window.addEventListener('load',onload);$%
+        \if at anim@nomouse\else
+          function onMouseDownWdgt(){$%
+            \@anim at wdgtDownJSString{#1}%
+          }$%
+          function onMouseUpWdgt(event){$%
+            \@anim at wdgtUpJSString{#1}%
+          }$%
+        \fi%
+      ]]>$%
+      </script>$%
+      </defs>%
+    }%
+  }
+\fi
+
+\endgroup % `$'--> newline in svg



More information about the tex-live-commits mailing list