Media Pipeline
Included is a built-in media pipeline:
uploads to storage (local or S3-compatible)
derivative generation (thumb/small/medium/large) via
sharpanimation support for Lottie (JSON) and SVG
optional optimization (WebP for images, compressed MP4 for videos)
category tagging + metadata for discovery
Key files
Controller:
app/controllers/media_controller.tsService:
app/services/media_service.tsStorage:
app/services/storage_service.tsVariant generation action:
app/actions/generate_media_variants_action.tsMedia field type (module props/custom fields):
app/fields/media.tsFrontend Renderer:
inertia/components/MediaRenderer.tsx
Supported Formats & Processing
Raster Images
JPG, PNG, WebP, GIF, AVIF are processed via sharp to generate size variants and optimized WebP versions.
Vector & Animations
SVG: Uploaded and served as-is. Supports dark-mode variant overrides.
Lottie: Supports
.jsonand.lottiefiles. Rendered on the frontend using@lottiefiles/lottie-player.
Video
MP4 and WebM support. Playback modes (autoplay, inline, modal) are stored in the media asset metadata. Videos can be optimized to a compressed MP4 format via ffmpeg.
MEDIA_VIDEO_OPTIMIZATION_CRF(default ~28)MEDIA_VIDEO_OPTIMIZATION_PRESET(default ~medium)
Derivatives configuration
Derivatives are configured with env:
MEDIA_DERIVATIVES
Default (if unset) in media_service.ts:
thumb:200x200_crop,small:400x,medium:800x,large:1600x
Notes:
_cropusesfit: cover(square crops, etc.)non-crop uses
fit: inside
Dark mode variants
Dark mode for media is handled in two ways:
Manual Overrides: Editors can upload a specific dark version of an image or SVG.
Automatic Generation: If no manual override is provided, the system can automatically generate a dark version of the original image by applying a tunable brightness and saturation transform.
Automatic Dark Base Generation
The CreateDarkBaseAction (app/actions/create_dark_base_action.ts) is responsible for generating these dark versions. It uses sharp to modulate the original image.
Configuration
You can tune the appearance of automatically generated dark variants via environment variables:
MEDIA_DARK_BRIGHTNESS(default ~0.55): Controls the brightness of the generated dark image (range: 0.1 to 2.0).MEDIA_DARK_SATURATION(default ~0.75): Controls the saturation of the generated dark image (range: 0 to 2.0).
These settings allow you to ensure that automatically darkened images still look good and maintain brand consistency without manual work for every asset.
Optimized Media
media_service can generate optimized derivatives for better web performance.
Images (WebP)
MEDIA_WEBP_QUALITY(default ~82)
Video (MP4)
MEDIA_VIDEO_OPTIMIZATION_CRF(default ~28, range 0-51)MEDIA_VIDEO_OPTIMIZATION_PRESET(default ~medium)FFMPEG_PATH(optional, custom path to ffmpeg binary)FFPROBE_PATH(optional, custom path to ffprobe binary)
How media is referenced by modules
Modules commonly use a prop schema like:
image: { type: 'media', storeAs: 'id' }
This means editors store a media asset id in props; renderers resolve it through the media API/service.
Storage Configuration
The media pipeline supports local and S3-compatible (specifically Cloudflare R2) storage. This is controlled by the STORAGE_DRIVER environment variable.
For detailed configuration instructions, see the Deployment Guide: Persistent Storage.
Migrating Storage Backends
If you are switching from local storage to Cloudflare R2, you can use the built-in migration command to sync your existing assets and update database references:
node ace migrate:media:r2
See the Deployment Guide for full details on the migration process.
AI-Generated Media
The media pipeline is integrated with AI agents for automated image generation:
Tools: Agents use the
generate_imageMCP tool to create new assets.Providers: Supports OpenAI (DALL-E) and Google (Imagen).
Staging: Generated images are automatically downloaded, optimized, and saved to the CMS media library before being staged in the post's review draft.
Config: Providers and models are configured at the agent level (see
providerMediaandmodelMediain the AI Agents documentation).
External Media Imports
The media pipeline supports importing assets directly from external URLs. This is particularly useful during content migrations:
Detection: The
DatabaseImportServiceandMigrationAgentautomatically detect URLs starting withhttpin media fields.Processing: When a URL is detected, the system downloads the file, performs standard optimization (WebP/MP4), and generates all configured variants.
Storage: The downloaded and processed asset is then uploaded to the configured storage driver (Local or R2) and registered in the
media_assetstable.
Operational notes
If you add new derivative specs, consider a backfill job to regenerate variants for existing assets.
If you change storage backends, ensure existing URLs remain valid or provide redirect/migration logic.