Media Pipeline
Adonis EOS includes 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
Adonis EOS handles dark mode for media 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).
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.