library(emphatic)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(tidyr)

# dimensions of data.frame
w <- 8
h <- 20

# Create an emphatic object
create_sinus <- function(xoff, yoff) {
  expand.grid(x=1:w, y=1:h) |>
    as.data.frame() |>
    mutate(val = cos((x - w/2)/w + xoff) + sin((y - h/3)/h + yoff) ) |>
    mutate(val = round(val, 3)) |>
    spread(x, val) |>
    select(-y) |>
    setNames(sprintf("% 7i", seq(w))) |>
    hl(ggplot2::scale_color_gradient2(), cols = all())
}

# Test
create_sinus(0, 0)
           1       2       3       4       5       6       7       8
1 0.651 0.689 0.713 0.720 0.713 0.689 0.651 0.598
2 0.699 0.738 0.761 0.769 0.761 0.738 0.699 0.646
3 0.748 0.787 0.810 0.818 0.810 0.787 0.748 0.695
4 0.798 0.836 0.859 0.867 0.859 0.836 0.798 0.745
5 0.847 0.886 0.909 0.917 0.909 0.886 0.847 0.794
6 0.897 0.936 0.959 0.967 0.959 0.936 0.897 0.844
7 0.947 0.986 1.009 1.017 1.009 0.986 0.947 0.894
8 0.997 1.036 1.059 1.067 1.059 1.036 0.997 0.944
9 1.047 1.085 1.109 1.116 1.109 1.085 1.047 0.994
10 1.096 1.135 1.158 1.166 1.158 1.135 1.096 1.043
11 1.145 1.184 1.207 1.215 1.207 1.184 1.145 1.093
12 1.194 1.232 1.256 1.264 1.256 1.232 1.194 1.141
13 1.242 1.280 1.304 1.311 1.304 1.280 1.242 1.189
14 1.289 1.327 1.351 1.359 1.351 1.327 1.289 1.236
15 1.335 1.374 1.397 1.405 1.397 1.374 1.335 1.282
16 1.380 1.419 1.442 1.450 1.442 1.419 1.380 1.327
17 1.424 1.463 1.486 1.494 1.486 1.463 1.424 1.372
18 1.467 1.506 1.529 1.537 1.529 1.506 1.467 1.414
19 1.509 1.547 1.571 1.578 1.571 1.547 1.509 1.456
20 1.549 1.587 1.611 1.618 1.611 1.587 1.549 1.496
# Loop over x,y and create a list of emphatic objects
groups <- purrr::map2(
  cos(seq(0, 2*pi , length.out = 60)),
  sin(seq(-2*pi, 2*pi, length.out = 60)),
  ~create_sinus(.x, .y)
)

# Save the list as an SVG animation to file
if (FALSE) {
  as_svg_anim(groups, duration = 0.1, playback = 'infinite') |>
    writeLines("sinus.svg")
}

# Play the SVG animation back in the Rstudio console
if (FALSE) {
  as_svg_anim(groups, duration = 0.1, playback = 'infinite', browsable = TRUE)
}