Processing Expert Article 10

Publishing & Exhibition

Export, sign, and deploy Processing sketches for gallery installations, from cross-platform applications to Raspberry Pi and OpenProcessing.

⏱ 45 min exhibition export Raspberry Pi deployment OpenProcessing installation

Getting a Processing sketch out of the IDE and into a gallery, venue, or online platform requires attention to runtime dependencies, operating system signing requirements, and the operational realities of unattended installation hardware. This article covers the full path from export to archival documentation.

Export Application

Processing’s built-in export bundles your sketch with a Java runtime for each platform. Go to File > Export Application and select the target platforms (macOS, Windows, Linux). The result is a self-contained directory per platform:

MySketch/
  application.macos/
    MySketch.app
  application.windows64/
    MySketch.exe
    lib/
  application.linux64/
    MySketch
    lib/

Important cross-platform considerations:

  • File paths: Use sketchPath("data/file.txt") or dataPath("file.txt"), never absolute paths. These resolve correctly regardless of platform.
  • Case sensitivity: Linux file systems are case-sensitive; Windows and macOS (by default) are not. A data/Image.png loaded as "image.png" works on Windows but fails silently on Linux.
  • Font embedding: Call createFont("MyFont.ttf", 18) and ensure the .ttf file is in the data/ folder. Do not rely on system fonts being installed.
  • Library natives: Third-party libraries with native components (OpenCV, Syphon) are platform-specific. Export for only the platforms the library supports.

Code Signing on macOS

Since macOS Catalina, unsigned applications are quarantined by Gatekeeper and refuse to open. For gallery deployment, you need an Apple Developer account and a signed, notarised build.

The export produces MySketch.app. Sign it:

# Sign all dylibs inside the app first
find MySketch.app/Contents -name "*.dylib" -exec \
  codesign --force --sign "Developer ID Application: Your Name (TEAMID)" {} \;

# Sign the app bundle
codesign --force --deep --options runtime \
  --sign "Developer ID Application: Your Name (TEAMID)" \
  --entitlements entitlements.plist \
  MySketch.app

A minimal entitlements.plist for a Processing sketch:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.security.cs.allow-jit</key><true/>
  <key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
  <key>com.apple.security.cs.disable-library-validation</key><true/>
</dict>
</plist>

Then notarise:

# Zip the app
zip -r MySketch.zip MySketch.app

# Submit for notarisation
xcrun notarytool submit MySketch.zip \
  --apple-id "you@example.com" \
  --team-id "YOURTEAMID" \
  --password "@keychain:AC_PASSWORD" \
  --wait

# Staple the ticket
xcrun stapler staple MySketch.app

Notarisation typically takes 1–5 minutes. The stapled app will open without Gatekeeper warnings on any Mac.

Raspberry Pi Deployment

A Raspberry Pi 4 (4GB RAM) runs Processing 4 adequately for 2D sketches without heavy shader work. Headless deployment with a fixed display server avoids requiring a keyboard at the venue.

Install Processing on Raspberry Pi:

curl https://processing.org/download/install-arm64.sh | sudo sh

Run headlessly with DISPLAY environment variable:

export DISPLAY=:0
/usr/local/bin/processing-java --sketch=/home/pi/sketches/MySketch \
  --run &

Auto-start on boot via systemd:

# /etc/systemd/system/mysketch.service
[Unit]
Description=Processing Installation Sketch
After=graphical.target

[Service]
User=pi
Environment=DISPLAY=:0
ExecStart=/usr/local/bin/processing-java \
  --sketch=/home/pi/sketches/MySketch --run
Restart=always
RestartSec=5

[Install]
WantedBy=graphical.target

Enable it:

sudo systemctl enable mysketch.service
sudo systemctl start  mysketch.service

The service restarts automatically after a crash. Use journalctl -fu mysketch.service to tail logs remotely over SSH.

Prevent display sleep:

# In /etc/xdg/lxsession/LXDE-pi/autostart, add:
@xset s off
@xset -dpms
@xset s noblank

Writing a Tech Rider

A tech rider specifies what you need from a venue. Precision prevents last-minute scrambles.

TECHNICAL REQUIREMENTS — "Subdivision" by Jane Doe

Hardware:
  - 1× Mac Mini M2, 8GB RAM, running macOS 14 (provided by artist)
    OR 1× Windows 11 PC, i7, 16GB RAM, GTX 3060 or equivalent (venue supplied)
  - 1× Full-HD projector (1920×1080), minimum 3000 ANSI lumens
  - HDMI cable, max run 5m (longer runs require active repeater)

Software:
  - Processing 4.3.1 (bundled in application export — no install needed)
  - No internet connection required after installation

Physical:
  - Dark room preferred; max ambient illuminance 50 lux
  - Projection surface: matte white wall or 130" screen, 16:9 ratio
  - Power: 1× standard outlet within 2m of computer

Runtime:
  - Resolution: 1920×1080 @ 60fps
  - Operating hours: continuous (sketch loops indefinitely)
  - Restart procedure: double-click MySketch.app; sketch enters fullscreen in 3s
  - Emergency stop: press Escape or close the window

Contact: jane@example.com  +44 7700 900000

Documenting Generative Work

Archival documentation for generative work captures both the process and specific instances.

Recording parameters per output file:

void saveDocumented() {
  String ts   = year() + nf(month(),2) + nf(day(),2) + "-" + nf(hour(),2) + nf(minute(),2);
  String base = sketchPath("archive/" + ts + "_seed" + seed);
  saveFrame(base + ".png");

  String[] meta = {
    "title=Subdivision v1.2",
    "seed=" + seed,
    "date=" + ts,
    "processingVersion=4.3.1",
    "sketchHash=" + sketchHash(),  // see below
    "width=" + width,
    "height=" + height,
    "params=" + exportParams()
  };
  saveStrings(base + ".txt", meta);
}

String sketchHash() {
  // MD5 or CRC of the main .pde file — ties output to exact code version
  try {
    java.io.File f = new java.io.File(sketchPath(sketchName + ".pde"));
    byte[] b = loadBytes(f.getAbsolutePath());
    java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
    byte[] hash = md.digest(b);
    StringBuilder sb = new StringBuilder();
    for (byte byt : hash) sb.append(String.format("%02x", byt));
    return sb.toString().substring(0, 8);
  } catch (Exception e) { return "unknown"; }
}

OpenProcessing.org

OpenProcessing hosts Processing and p5.js sketches as interactive browser applets. Processing 4 exports to JavaScript via its JavaScript mode, but the most reliable route for complex sketches is p5.js rewrite.

For pure Processing Java sketches, upload the .pde files directly. OpenProcessing handles compilation server-side for simpler sketches. For library-dependent work, a libraries.txt in the upload specifies which libraries to include.

GitHub for Processing Sketches

A .gitignore for a Processing project:

# Processing build output
application.linux64/
application.macos/
application.windows64/
*.class

# Output files (large — track separately or exclude)
output/*.png
output/*.svg
archive/

# macOS
.DS_Store

# Java
*.jar
!data/*.jar

Keep data/ assets in the repo for reproducibility. For large asset files (video, high-res images), use Git LFS:

git lfs install
git lfs track "*.png" "*.mov" "*.wav"
git add .gitattributes

Complete Exhibition Startup Script

A shell script that initialises the environment, verifies the display, and launches the sketch with logging:

#!/usr/bin/env bash
# launch-installation.sh

SKETCH_DIR="$HOME/sketches/MySketch"
LOG_FILE="$HOME/logs/installation-$(date +%Y%m%d-%H%M%S).log"
PROCESSING_BIN="/usr/local/bin/processing-java"

mkdir -p "$HOME/logs"

echo "=== Installation startup $(date) ===" | tee -a "$LOG_FILE"

# Ensure display is up
export DISPLAY=:0
if ! xdpyinfo >/dev/null 2>&1; then
  echo "ERROR: No display on :0. Is Xorg running?" | tee -a "$LOG_FILE"
  exit 1
fi

# Disable screen blanking
xset s off -dpms 2>>"$LOG_FILE"

# Kill any stale instance
pkill -f "processing-java" 2>/dev/null
sleep 2

echo "Launching sketch..." | tee -a "$LOG_FILE"

# Run indefinitely; restart on crash
while true; do
  $PROCESSING_BIN --sketch="$SKETCH_DIR" --run >> "$LOG_FILE" 2>&1
  EXIT_CODE=$?
  echo "Sketch exited with code $EXIT_CODE at $(date). Restarting in 5s..." \
    | tee -a "$LOG_FILE"
  sleep 5
done

Make it executable and drop a systemd unit around it as described in the Raspberry Pi section. Set up remote SSH access so you can pull logs and restart the sketch during the exhibition without being physically present.

Exhibition Checklist

Before opening day, run through this list:

Pre-install:
[ ] Application signed and notarised (macOS) or tested on target OS
[ ] All data files present in exported application
[ ] sketch runs for 8+ hours without memory leak (check with top/Activity Monitor)
[ ] frameRate() measured at venue resolution and projector

Hardware:
[ ] Power connected to UPS (uninterruptible power supply)
[ ] Display auto-on after power cut confirmed
[ ] Startup script set to auto-launch on login
[ ] Remote SSH access tested from external network

Opening:
[ ] Emergency stop procedure briefed to gallery staff
[ ] Log file location noted for diagnosis
[ ] Contact number left with venue
[ ] Archive of current output images stored off-site

An installation that runs unattended for weeks requires the same discipline as any production software deployment. The checklist, the startup script, and the tech rider are as much a part of the work as the code itself.