Is animate package compatible with htlatex

Edit: here is the final animation.

This won't be easy. I cannot even display your PDF animation on my machine, because animate package uses some JavaScript in PDF trickery which is not supported by most PDF readers except Acrobat Reader and few others.

Anyway, there are two different tasks which need to be done: first is to export your animation steps as separate images, the second is to animate them on the HTML page. I will address only the first task today, I will look at the second one later.

So what needs to be done to get the animation steps as images? First of all, we should fix the compilation errors. There are two sources of errors. First is the TikZ output driver for tex4ht, the second is pdfbase package required by animated, which redefines some internal LaTeX command used also by tex4ht.

To fix the TikZ issue, we may use an alternative driver which uses the dvisvgm command for conversion to SVG format, which is ideal for vector graphics on Web. Save the following file as pgfsys-tex4ht.def:

% Copyright 2006 by Till Tantau
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.

\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/systemlayer/pgfsys-tex4ht.def,v 1.25 2013/08/06 17:46:08 tantau Exp $



% Driver commands for tex4ht

%
% Load common pdf commands:
%
  %\input pgfsys-dvisvgm.def
  \input pgfsys-dvips.def

%
% tex4ht-specific stuff:
%

\newcount\pgf@sys@svg@picnum

% configure the output picture format to svg
\AtBeginDocument{
  \Configure{Picture}{.svg}
}


% Make the code inserted by tex4ht configurable

\NewConfigure{tikzpicture}{2}
\Configure{tikzpicture}{%
  % \ifvmode\IgnorePar\fi\EndP%\HtmlParOff
  \Picture*{}
}{\EndPicture}

\let\orig@pgfsys@begin\pgfsys@beginpicture
\let\orig@pgfsys@end\pgfsys@endpicture
\def\pgf@sys@postscript@header#1{{\special{! #1}}}
\def\pgfsys@beginpicture{%
  \bgroup
  \csname a:tikzpicture\endcsname
  \pgf@sys@postscript@header{
    /pgfsc{}bind def% stroke color is empty by default
    /pgffc{}bind def% fill color is empty by default
    /pgfstr{stroke}bind def%
    /pgffill{fill}bind def%
    /pgfeofill{eofill}bind def%
    /pgfe{a dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath}bind def% rectangle
    /pgfw{setlinewidth}bind def% setlinewidth
    /pgfs{save pgfpd 72 Resolution div 72 VResolution div neg scale 
      magscale{1 DVImag div dup scale}if 
      pgfx neg pgfy neg translate pgffoa .setopacityalpha}bind def% save
    /pgfr{pgfsd restore}bind def %restore
    userdict begin%
    /pgfo{pgfsd /pgfx currentpoint /pgfy exch def def @beginspecial}bind def %open
    /pgfc{newpath @endspecial pgfpd}bind def %close
    /pgfsd{globaldict /pgfdelta /delta where {pop delta} {0} ifelse put}bind def% save delta
    /pgfpd{/delta globaldict /pgfdelta get def}bind def % put delta
    /.setopacityalpha where {pop} {/.setopacityalpha{pop}def} ifelse % install .setopacityalpha 
    /.pgfsetfillopacityalpha{/pgffoa exch def
      /pgffill{gsave pgffoa .setopacityalpha fill 1 .setopacityalpha newpath fill grestore newpath}bind def
      /pgfeofill{gsave pgffoa .setopacityalpha eofill 1 .setopacityalpha newpath eofill grestore newpath}bind def}bind def
    /.pgfsetstrokeopacityalpha{/pgfsoa exch def /pgfstr{gsave pgfsoa .setopacityalpha stroke grestore newpath}bind def}bind def
    /pgffoa 1 def
    /pgfsoa 1 def
    end
  }%
  \orig@pgfsys@begin%
}%


\def\pgfsys@endpicture{%
  % Save the bounding box
  %\printdim%
  \orig@pgfsys@end%
  \csname b:tikzpicture\endcsname%
  \egroup
  \par% FIXME : was '\Par' but that seems to be undefined!?
}%


\endinput


%%% Local Variables: 
%%% mode: latex
%%% End: 

The pdfbase issue can be fixed using usepackage.4ht file:

% usepackage.4ht (2017-10-21-16:16), generated from tex4ht-4ht.tex
% Copyright 2003-2009 Eitan M. Gurari
% Copyright 2009-2017 TeX Users Group
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3c of this license or (at your option) any
% later version. The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions
% of LaTeX version 2005/12/01 or later.
%
% This work has the LPPL maintenance status "maintained".
%
% The Current Maintainer of this work
% is the TeX4ht Project <http://tug.org/tex4ht>.
%
% If you modify this program, changing the
% version identification would be appreciated.
   \def\:temp{tex4ht}\ifx \:temp\@currname
   \:warning{\string\usepackage{tex4ht} again?}
   \def\:temp#1htex4ht.def,tex4ht.sty#2!*?: {\def\:temp{#2}}
\expandafter\:temp \@filelist htex4ht.def,tex4ht.sty!*?: %
\ifx \:temp\empty  \else
   \:warning{if
    \string\RequirePackage[tex4ht]{hyperref} or
    \string\usepackage[tex4ht]{hyperref} was
    used try instead, repectively,
    \string\RequirePackage{hyperref} or
    \string\usepackage{hyperref}}
\fi

\fi
\gdef\a:usepackage{\use:package xr,xr-hyper,savetrees,biblatex,xeCJK,fontspec,tikz,pdfbase,,!*?: }
\gdef\use:package#1,{%
   \if :#1:\def\:temp##1!*?: {}\else
      \def\:temp{#1}\ifx \@currname\:temp
             \def\:temp##1!*?: {\input usepackage.4ht  }%
      \else \let\:temp=\use:package \fi
   \fi \:temp}
\def\:temp{xr}\ifx \@currname\:temp
   \AtEndOfPackage{\let\XR:\XR@
   \def\XR@[#1]#2{%
    \Configure{AtBeginDocument}{\XR:[#1]{#2}}{}}%
}

\fi
\def\:temp{xr-hyper}\ifx \@currname\:temp
   \def\eat:optional[#1]{}
\AtEndOfPackage{\let\XR:\XR@
   \def\XR@[#1]#2{%
     \Configure{AtBeginDocument}{\XR:[#1]{#2}}{}\@ifnextchar[\eat:optional{}}%
}

\fi
\def\:temp{savetrees}\ifx \@currname\:temp
\:dontusepackage{savetrees}
\fi
\def\:temp{biblatex}\ifx \@currname\:temp
\AtEndOfPackage{%
  \def\blx@mknoautolang{%
    \blx@lbxinput{\blx@languagename}%
    {}{}%
  }%
}
\fi
\def\:temp{xeCJK}\ifx \@currname\:temp
\:dontusepackage{xeCJK}
\AtEndOfPackage{%
  \RequirePackage{fontspec}
}
\DeclareDocumentCommand\setCJKmainfont{o m o}{}
\let\setCJKsansfont\setCJKmainfont
\let\setCJKmonofont\setCJKmainfont

\DeclareDocumentCommand\setCJKfamilyfont {m o m }{}
\DeclareDocumentCommand\newCJKfontfamily {o m o m}{\expandafter\gdef\csname #2\endcsname{\relax}}

\DeclareDocumentCommand\xeCJKsetup{m}{}
% }
\AtBeginDocument{%
  \xeuniuseblock{CJK}
}
\fi
\def\:temp{fontspec}\ifx \@currname\:temp
  \ifdefined\fontspec
    \:dontusepackage{fontspec}
  \else
    \input usepackage-fontspec.4ht
  \fi
\fi
\def\:temp{tikz}\ifx \@currname\:temp
\AtEndOfPackage{%
\let\use:tikzlibrary\usetikzlibrary
\def\find:externalize#1external#2\@nil{%
\if\relax#2\relax\else
  \let\tikz:externalize\tikzexternalize
  \renewcommand\tikzexternalize[1][]{\tikz:externalize[##1,mode=only graphics]}
    \tikzset{%
      tex4ht inc/.style={%
        /pgf/images/include external/.code={%
          \includegraphics[]{####1.pdf}%
        }%
      }
    }
    \tikzset{tex4ht inc}
  \fi
}
\renewcommand\usetikzlibrary[1]{%
  \use:tikzlibrary{#1}%
  \find:externalize#1external\@nil%
}
}
\fi

\def\:temp{pdfbase}\ifx\@currname\:temp
\AtEndOfPackage{%
\let\old:outputpage\@outputpage
\def\@outputpage{\old:outputpage{}}
}
\fi

\endinput

Place both files in the directory with your TeX file.

We also need some configuration file for the animate package, to request the steps to image conversion. The animate.4ht file:

\NewConfigure{animinline}{2}
\let\:anim:xinline\@anim@xinline
\def\@anim@xinline#1#2#3#4{\a:animinline\:anim:xinline{#1}{#2}{#3}{#4}\b:animinline}

\Hinput{animate}

This configuration redefines the code used for rendering of the steps and inserts two configurable hooks. We can configure these hooks to render the contained content as image. These configurations can be done in a configuration file, myconfig.cfg:

\Preamble{xhtml,html5,svg}
\Configure{animinline}{\Picture+{}}{\EndPicture}
\ConfigureEnv{animateinline}{%
  \ifvmode\IgnorePar\fi\EndP\HCode{<div class="animateinline">}%
  \Configure{tikzpicture}{}{}%
}{\ifvmode\IgnorePar\fi\EndP\HCode{</div>}}{}{}
\Css{.animateinline img{
  display:none;
 }}

\Css{.animateinline img:first-child{
   display:block;
 }}

% register the js file for processing
\special{t4ht+@File: animate.js}
\Configure{@/BODY}{\HCode{<script type="text/javascript" src="animate.js"></script>}}
\begin{document}
\EndPreamble

The \Configure{animinline}{\Picture+{}}{\EndPicture} code requests the image rendering of the animation steps. \ConfigureEnv{animateinline} inserts <div class="animateinline"> element, which will be used for the HTML animation later.

The CSS code

\Css{.animateinline img{
  display:none;
 }}

\Css{.animateinline img:first-child{
   display:block;
 }}

will display only the first image and hide the rest. We will use JavaScript to continuously make animation effect by showing the hidden images.

The JavaScript code is requested using:

\special{t4ht+@File: animate.js}
\Configure{@/BODY}{\HCode{<script type="text/javascript" src="animate.js"></script>}}

The first line register the file animate.js to be processed by tex4ht, the second will include it at the end of document body.

The animate.js:

function add_animations(cls){
  var elements = document.querySelectorAll(cls);
  elements.forEach(function(value, index, obj){
    console.log(value + ", " + index + ", "+ obj + ", "+ this);
    var next = 0;
    var reset = function(){next=0};
    var curr_obj = obj[index];
    var images = curr_obj.querySelectorAll("img");
    setInterval(function(){
      images.forEach(function(val, i, newobj){
        newobj[i].style.display="none";
      });
      if(next < images.length-1){ next++} else {reset()}
      console.log("next: "+ next);
      images[next].style.display = "block";
    }, 100);
  });
}

add_animations(".animateinline");

You can compile your document using

make4ht -um draft -c myconfig.cfg filename.tex

And this is the result (not animated here, unfortunately):

enter image description here enter image description here

The animated version can be seen here


Package animate is now compatible with htlatex (tex4ht).

As of version [2018/11/20] package animate can produce self-contained, standalone animated SVG files that can be embedded into HTML using the <object> HTML tag or opened directly in a contemporary Web browser, such as Firefox, Chromium or Opera. It makes use of M. Gieseking's dvisvgm utility, which is part of TeXLive and MikTeX.


Click the image to load the SVG:


  1. To produce animated SVG, add global option dvisvgm to the article document class and suppress the page number. Run one of latex, lualatex --output-format=dvi, or xelatex -no-pdf on the source file, then dvisvgm --exact --font-format=woff on the previously generated DVI or XDV (by xelatex) file.

    \documentclass[dvisvgm]{article}
    \usepackage{animate}
    \usepackage{tikz}
    \usepackage{pgfplots}
    \pgfplotsset{compat=newest}
    \usepgfplotslibrary{polar}
    
    \pgfplotsset{
    paxis/.style={width=5cm,height=5cm,ymin = 0,ymax = 1.5*\offset,tick align=outside,xticklabels=\empty,yticklabels=\empty,xmajorgrids=false,ymajorgrids=false},
    refer/.style={red,domain=0:360,samples=36},
    points/.style={blue,mark={*},samples at={0}},
    }
    
    \pagestyle{empty}
    
    \begin{document}
    
    \def\offset{5}
    \begin{animateinline}[autoplay,loop,controls,
      begin={%
        \begin{tikzpicture}
          \begin{polaraxis}[paxis,xshift=0]
          \addplot[refer] (x,{\offset)});
      },
      end={%
          \end{polaraxis}
        \end{tikzpicture}%
      },
    ]{10}
      \multiframe{30}{rt=0+1}{
        \def\anglet{0.1*\rt*360}
        \addplot[points] ({x+\anglet},\offset);
      }
    \end{animateinline}
    
    \end{document}
    
  2. Embed the animated SVG into the document by means of an <object> HTML tag placed inside a \HCode{...} command and compile the document with make4ht -uf html5:

    ...
    \HCode{%
      <object type="image/svg+xml" data="animatedImage.svg">
        <!-- fallback & search engine indexing -->
        <img src="animatedImage.svg" />
      </object>
    }
    ...