library(artpipelines)
# Check a .procreate file
is_procreate_file("path/to/artwork.procreate")
# [1] TRUE
# Check an extracted directory
is_procreate_dir("path/to/extracted/canvas/")
# [1] TRUEOverview
Procreate is a popular digital art application for iPad. Its .procreate canvas files are ZIP archives containing layers, artwork data, metadata, and an embedded timelapse recording of the creation process.
When users upload artwork to the Artalytics platform, we need to verify that:
- The file is a valid Procreate canvas (correct structure)
- The canvas contains actual artwork (not blank or empty)
- There’s evidence of genuine creative work (timelapse, edits over time)
This vignette explains how to use assess_procreate_canvas() to perform this validation and interpret its results.
Why Validation Matters
Before committing resources to process an artwork through the full pipeline (CDN uploads, AI analysis, database population), validation catches:
- Corrupted files - Files that claim to be .procreate but aren’t valid
- Empty canvases - Valid structure but no actual artwork
- Minimal content - Canvas opened but barely used
- Fraudulent submissions - Files lacking evidence of genuine creation
Basic Validation
Quick Structure Check
For a fast check of whether a file is a valid Procreate canvas:
These functions verify basic structural requirements without deep analysis.
Comprehensive Assessment
For full validation including creative evidence:
result <- assess_procreate_canvas("path/to/artwork.procreate", verbose = TRUE)
# Console output:
# [assess_procreate_canvas] procreate=TRUE | importable=TRUE | creative=definite |
# class=DEFINITELY_CREATIVE | mp4=12 | tiles=48Understanding the Results
The assessment returns a list with multiple fields:
Classification
The classification field provides a categorical verdict:
| Classification | Meaning |
|---|---|
DEFINITELY_CREATIVE |
Strong evidence: has timelapse AND sufficient tiles |
PROBABLY_CREATIVE |
Moderate evidence: has timelapse OR sufficient tiles |
INDETERMINATE |
Valid structure but weak creative indicators |
NOT_CREATIVE |
Appears empty, blank, or invalid |
result$classification
# [1] "DEFINITELY_CREATIVE"Creative Evidence
The creative_evidence field indicates the strength of evidence:
| Evidence Level | Interpretation |
|---|---|
definite |
Multiple strong signals (timelapse + tiles) |
probable |
At least one strong signal |
weak |
Only timestamp dispersion detected |
none |
No creative indicators found |
result$creative_evidence
# [1] "definite"Structural Validity
# Is this a valid Procreate canvas structure?
result$is_procreate
# [1] TRUE
# Can it likely be opened in Procreate?
result$importable_probable
# [1] TRUEQuantitative Metrics
# Non-empty timelapse video segments
result$n_mp4_nonempty
# [1] 12
# Raster tile/chunk files (more = more content)
result$n_tile_files
# [1] 48
# Distinct edit timestamps (file modification times)
result$n_distinct_edit_seconds
# [1] 156Diagnostic Information
# Reasons for any flags or downgrades
result$reasons
# character(0) # Empty if no issues
# Full file listing from the canvas
head(result$df)
#> name size mtime_local kind
#> 1: Document.archive 15234 2024-03-15 14:23:17 other
#> 2: video/00.mp4 234567 2024-03-15 14:25:00 mp4
#> 3: layers/0/data/tile_00.raw 65536 2024-03-15 14:30:00 tileDetection Signals
The function uses multiple signals to assess creative evidence:
1. Timelapse Video Segments
Procreate records a timelapse by default. The presence of non-empty .mp4 files in the video/ directory is strong evidence of drawing activity.
# Count of timelapse segments > 0 bytes
result$n_mp4_nonempty
# High values (10+) indicate substantial drawing time2. Raster Tile Count
Procreate stores artwork as tiled image chunks. More tiles generally indicate: - Larger canvas size - More layers with content - More extensive painting
# Default threshold: 25 tiles for "creative" classification
result$n_tile_files
# Values below threshold may indicate minimal content3. Timestamp Dispersion
Even without timelapse, edits over time leave traces in file modification timestamps:
# Distinct seconds with file modifications
result$n_distinct_edit_seconds
# Default threshold: 10 seconds for weak creative evidenceTuning Thresholds
Adjust sensitivity based on your use case:
# More lenient (catch more edge cases as creative)
result <- assess_procreate_canvas(
path = "path/to/canvas.procreate",
min_tiles = 10L, # Lower tile threshold (default: 25)
min_edit_seconds = 5L # Lower timestamp threshold (default: 10)
)
# More strict (higher bar for creative classification)
result <- assess_procreate_canvas(
path = "path/to/canvas.procreate",
min_tiles = 50L,
min_edit_seconds = 30L
)Handling Edge Cases
Empty or Blank Canvas
A canvas that was created but never drawn on:
result <- assess_procreate_canvas("blank-canvas.procreate")
result$is_procreate
# [1] TRUE - Valid structure
result$classification
# [1] "NOT_CREATIVE"
result$creative_evidence
# [1] "none"
result$n_mp4_nonempty
# [1] 0 - No timelapse (never opened for drawing)
result$n_tile_files
# [1] 1 - Just the base layerCorrupted or Invalid File
A file that isn’t a valid Procreate canvas:
# Non-existent file
assess_procreate_canvas("nonexistent.procreate")
# Error: Path not found: nonexistent.procreate
# Wrong file type
assess_procreate_canvas("image.png")
# Returns with is_procreate = FALSE, classification = "NOT_CREATIVE"Minimal Content
A canvas with some activity but below thresholds:
result <- assess_procreate_canvas("quick-sketch.procreate")
result$classification
# [1] "INDETERMINATE"
result$creative_evidence
# [1] "weak"
result$reasons
# [1] "No MP4 segments, insufficient tiles, low edit dispersion"Integration with Pipelines
Pre-Pipeline Validation
validate_before_pipeline <- function(canvas_path) {
result <- assess_procreate_canvas(canvas_path, verbose = FALSE)
if (result$classification == "NOT_CREATIVE") {
stop("Canvas appears empty or invalid. Upload rejected.")
}
if (result$classification == "INDETERMINATE") {
warning("Canvas has weak creative evidence. Manual review recommended.")
}
# Return assessment for logging
invisible(result)
}
# Use before running full pipeline
validate_before_pipeline("path/to/submission.procreate")
run_pipeline(...)Batch Validation
canvas_files <- list.files("uploads/", pattern = "\\.procreate$", full.names = TRUE)
assessments <- lapply(canvas_files, function(f) {
tryCatch(
assess_procreate_canvas(f, verbose = FALSE),
error = function(e) list(path = f, error = e$message)
)
})
# Filter to creative canvases only
creative <- Filter(
function(x) !is.null(x$classification) &&
x$classification %in% c("DEFINITELY_CREATIVE", "PROBABLY_CREATIVE"),
assessments
)
length(creative)
# [1] 47 of 50 submissions passed validationRelated Functions
-
is_procreate_file()- Quick structural check for .procreate files -
is_procreate_dir()- Quick structural check for extracted directories -
verify_creation_period()- Extract defensible creation timestamps (see Creation Window vignette)
Next Steps
- Creation Window - Extract provenance timestamps from validated canvases
- Quickstart - Run the full processing pipeline
- Function Reference - Complete API documentation
