Introduction to animejs

Overview

animejs provides R bindings to Anime.js v4, a JavaScript animation library. It produces self-contained HTML widgets via the htmlwidgets package, which render in browser environments like RStudio Viewer, R Markdown documents, Quarto reports, and Shiny applications.

The package has three conceptual layers:

  1. Animationsanime_animate() describes a single animation; anime_timeline() and anime_add() accumulate a multi-segment animation specification in R.
  2. Propertiesanime_from_to() and anime_keyframes() describe how individual CSS/SVG properties move over time.
  3. Renderinganime_render() serialises the specification and wraps it in an htmlwidget.

A minimal example

Any SVG whose elements can be identified by a valid CSS selector can be targeted directly.

library(animejs)

svg_src <- '
<svg viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg">
  <circle data-animejs-id="c1" cx="50"  cy="100" r="20" fill="#4e79a7"/>
  <circle data-animejs-id="c2" cx="120" cy="100" r="20" fill="#f28e2b"/>
  <circle data-animejs-id="c3" cx="190" cy="100" r="20" fill="#e15759"/>
</svg>
'

anime_timeline(
  duration = 800,
  ease = anime_easing_elastic(),
  loop = TRUE
) |>
  anime_add(
    selector = anime_target_css("circle"),
    props = list(
      translateY = anime_from_to(-80, 0),
      opacity = anime_from_to(0, 1)
    ),
    stagger = anime_stagger(150, from = "first")
  ) |>
  anime_add(
    selector = anime_target_id("c2"),
    props = list(r = anime_from_to(20, 40)),
    offset = "+=200"
  ) |>
  anime_playback(controls = TRUE) |>
  anime_render(svg = svg_src, width = "360px")

Single animations

anime_animate() is the R equivalent of Anime.js v4’s animate(targets, parameters): one set of property animations applied to one selector, without a timeline.

anime_animate(
  selector = anime_target_css("circle"),
  props = list(
    translateY = anime_from_to(-60, 0),
    opacity = anime_from_to(0, 1)
  ),
  ease = anime_easing_spring(),
  stagger = anime_stagger(120)
) |>
  anime_render(svg = svg_src, width = "360px")

Single animations support the same playback modifiers, event callbacks, and rendering options as timelines.

Timelines

anime_timeline() initialises an animation timeline. The duration, ease, and delay arguments set defaults that apply to every segment; individual segments may override them via anime_add().

tl <- anime_timeline(
  duration = 1000,
  ease = anime_easing("Cubic", "inOut"),
  loop = TRUE
)

anime_add() appends one segment – a set of property animations applied to a CSS selector. The offset argument positions the segment on the timeline: "+=0" (default) starts immediately after the previous segment; "+=200" inserts a 200 ms gap.

Property animations

From/to

anime_from_to() is the simplest property descriptor: a start value and an end value, with an optional CSS unit and per-property easing override.

anime_from_to(0, 1) # opacity: 0 → 1
anime_from_to(0, 100, "px") # translateX: "0px" → "100px"
anime_from_to(0, 1, ease = anime_easing_spring()) # per-property easing

Keyframes

anime_keyframes() accepts two or more positional values. Bare values are used as to values; lists may additionally specify ease, duration, and delay per keyframe.

# Bare numeric keyframes
anime_keyframes(0, 1, 0.5)

# List-based keyframes with per-keyframe easing
anime_keyframes(
  list(to = 0),
  list(to = 1, ease = "outQuad", duration = 400),
  list(to = 0.5, ease = anime_easing_bezier(0.4, 0, 0.2, 1))
)

Staggering

anime_stagger() distributes animation start times across the elements matched by the selector. It is passed to the stagger argument of anime_add() or anime_animate().

anime_add(
  tl,
  selector = ".bar",
  props = list(scaleY = anime_from_to(0, 1)),
  stagger = anime_stagger(80, from = "center")
)

The start argument adds a base delay before the staggered delays, and reversed = TRUE reverses the stagger order. For two-dimensional grid layouts, supply grid = c(rows, cols) and optionally axis = "x" or axis = "y".

Easing

All easing constructors return anime_easing objects that map onto their Anime.js v4 equivalents:

Constructor Anime.js v4 equivalent
anime_easing("Quad", "out") "outQuad"
anime_easing_elastic() "outElastic(1,0.3)"
anime_easing_back() "outBack(1.70158)"
anime_easing_spring() spring({bounce: .5, duration: 628})
anime_easing_bezier(0.4, 0, 0.2, 1) cubicBezier(0.4, 0, 0.2, 1)
anime_easing_steps(10) steps(10)

Plain Anime.js v4 easing name strings (e.g. "inOutSine", "outElastic(1,0.3)") are also accepted wherever an anime_easing object is expected. Note that Anime.js v4 has removed the string syntax for cubic bezier, steps, and spring easings – the R constructors handle this automatically by reconstructing the corresponding function calls in JavaScript.

Playback

anime_playback() sets looping, direction, speed, and UI controls on a timeline or single animation. Arguments left as NULL keep the settings already stored on the object.

tl |>
  anime_playback(
    loop = TRUE,
    loop_delay = 250,
    alternate = TRUE,
    playback_rate = 1.5,
    controls = TRUE
  ) |>
  anime_render(svg = svg_src)

Setting controls = TRUE injects a play/pause button and a scrub slider into the widget.

Event callbacks

anime_on() registers a global JavaScript function as a lifecycle callback. Inject the function into the page via htmltools::tags$script().

tl |>
  anime_on("onComplete", "myOnCompleteHandler") |>
  anime_render(svg = svg_src)

Valid events are "onBegin", "onBeforeUpdate", "onUpdate", "onRender", "onLoop", "onPause", and "onComplete", matching the Anime.js v4 callback API.

Shiny

animejsOutput() and renderAnimejs() embed widgets in Shiny applications:

library(shiny)

ui <- fluidPage(
  sliderInput("duration", "Duration (ms)", 200, 2000, 800),
  animejsOutput("anim", height = "200px")
)

server <- function(input, output, session) {
  output$anim <- renderAnimejs({
    anime_animate(
      selector = anime_target_css("circle"),
      props = list(opacity = anime_from_to(0, 1)),
      duration = input$duration
    ) |>
      anime_render(svg = svg_src)
  })
}

shinyApp(ui, server)

Saving widget output

For reproducible documents the widget can be saved to a self-contained HTML file:

widget <- anime_render(tl, svg = svg_src)
htmlwidgets::saveWidget(widget, "animation.html", selfcontained = TRUE)