Skip to contents

Overview

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:

  1. The file is a valid Procreate canvas (correct structure)
  2. The canvas contains actual artwork (not blank or empty)
  3. 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:

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] TRUE

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=48

Understanding 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] TRUE

Quantitative 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] 156

Diagnostic 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   tile

Detection 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 time

2. 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 content

3. 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 evidence

Tuning 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 layer

Corrupted 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 validation

Next Steps