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")
)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:
- System Requirements: ImageMagick++ is installed (see Get Started)
- Environment Variables: Database and CDN credentials are configured
- 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():
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
- Architecture - Understand sub-module structure
- Storytelling Engine - Learn about journey insights
