Skip to contents

Overview

This guide details how to embed modFrames in a Shiny application. As a module package, modFrames requires proper integration with parent app infrastructure to function correctly.

Prerequisites

Before integrating modFrames, ensure:

  1. System Requirements: ImageMagick++ is installed (see Get Started)
  2. Environment Variables: Database and CDN credentials are configured
  3. Dependencies: {artutils}, {artcore}, and all R package dependencies are installed

Step 1: Install the Package

# Ensure GITHUB_PAT is set for private repo access
Sys.setenv(GITHUB_PAT = "ghp_xxxx...")

# Install modFrames and dependencies
pak::pkg_install("artalytics/modFrames")

Step 2: Create the UI

Add the module UI to your app using modFramesUI():

library(shiny)
library(bslib)
library(modFrames)

ui <- bslib::page_fluid(
  theme = bslib::bs_theme(version = 5),

  # modFrames provides its own CSS and dark mode toggle

  modFramesUI("frames")
)

Key UI Features:

  • Custom CSS stylesheets are automatically included
  • Bootstrap 5 tooltips are initialized via JavaScript
  • Dark mode toggle appears in the top-right corner
  • The module renders timelapse controls and frame comparison cards

Step 3: Prepare Reactive Data

modFrames requires specific reactive data from the parent app. Create a reactiveValues object with the expected structure:

server <- function(input, output, session) {
  # Shared reactive context
  r <- reactiveValues()

  # Populate when artwork selection changes
  observe({
    req(input$artist_selector, input$artwork_selector)

    # get_appdata() fetches all required data including frame_stats
    r$appdata <- artutils::get_appdata(
      artist = input$artist_selector,
      artwork = input$artwork_selector
    )
  })

  # Initialize the module
  modFramesServer("frames", r)
}

Step 4: Understand the Data Requirements

The module reads from r$appdata$artwork$frame_stats, which is a data.table with 21 columns populated by artutils::get_frame_analytics().

Required Data Path:

r$appdata$
├── artwork$
│   ├── stats$
│   │   ├── artist_uuid  # Character: Artist UUID
│   │   └── art_uuid     # Character: Artwork UUID
│   └── frame_stats      # data.table: 21-column frame analytics
└── config$
    └── n_frames         # Numeric: Total frame count

Frame Stats Columns (all 21):

  • art_uuid, artist_uuid, frame
  • elapsed_minutes, elapsed_hours, cumulative_strokes, estimated_bpm
  • unique_colors, total_pixels, dominant_hex, dominant_pixels
  • color_diversity, avg_red, avg_green, avg_blue
  • colors_added, colors_removed, pixels_added, palette_change_score
  • technique_phase, created_utc

Step 5: Integration with appPlatform

In the full appPlatform context, modFrames is instantiated alongside other modules. The parent app manages:

  • Artwork selection and navigation
  • Shared reactive context (r)
  • Global styling and theming
# Typical appPlatform pattern
server <- function(input, output, session) {
  r <- reactiveValues(
    artist = NULL,
    artwork = NULL,
    appdata = NULL
  )

  # Artist/artwork selection updates
  observe({
    r$artist <- input$artist_uuid
    r$artwork <- input$artwork_uuid
  })

  # Fetch appdata when selection changes
  observe({
    req(r$artist, r$artwork)
    r$appdata <- artutils::get_appdata(r$artist, r$artwork)
  })

  # Initialize modules
  modGalleryServer("gallery", r)
  modFramesServer("frames", r)
  modBrowseServer("browse", r)
}

Error Handling

Missing Frame Stats

If frame_stats is missing or empty, the module will fail to render. Ensure the artwork has been processed by artpipelines::createFrameAnalytics().

# Check if frame_stats exists
observe({
  if (is.null(r$appdata$artwork$frame_stats)) {
    showNotification(
      "Frame analytics not available for this artwork",
      type = "error"
    )
  }
})

ImageMagick Errors

Frame difference images require ImageMagick. If you see errors like “Error in magick_image_read”, verify ImageMagick++ is installed:

# Test magick functionality
magick::magick_config()

Complete Example

Here is a complete, minimal integration:

library(shiny)
library(bslib)
library(modFrames)
library(artutils)

# Test UUIDs
ARTIST <- "746b8207-72f5-4ab6-8d19-a91d03daec3d"
ARTWORK <- "99da02ea-1ac0-4ea0-bfb9-e11a485b599b"

ui <- bslib::page_fluid(
  theme = bslib::bs_theme(version = 5),
  modFramesUI("frames")
)

server <- function(input, output, session) {
  r <- reactiveValues()

  # Load data on startup
  observe({
    r$appdata <- artutils::get_appdata(ARTIST, ARTWORK)
  })

  modFramesServer("frames", r)
}

shinyApp(ui, server)

Next Steps