Assets
Media Library
Section titled “Media Library”The admin includes a media library at /admin/assets with:
- Grid view with thumbnails
- Folder organization (create, rename, delete, drag-to-move)
- Upload via button or drag-and-drop
- Alt text editing
- Focal point selector (click image to set crop center)
Image Fields
Section titled “Image Fields”Image fields render an upload button and a browse dialog that connects to the media library. The stored value is the file URL (/uploads/filename.ext).
Storage
Section titled “Storage”Files are stored in public/uploads/ by default. Asset metadata (filename, mime type, size, alt, focal point) is stored in the cms_assets table.
| Method | Endpoint | Description |
|---|---|---|
POST | /api/cms/assets/upload | Upload file (multipart/form-data) |
GET | /api/cms/assets | List assets |
GET | /api/cms/assets/:id | Get single asset |
PATCH | /api/cms/assets/:id | Update metadata |
DELETE | /api/cms/assets/:id | Delete asset and file |
List parameters
Section titled “List parameters”| Param | Type | Description |
|---|---|---|
limit | number | Max results (default 50) |
offset | number | Skip N results |
folder | string | Filter by folder ID (empty string for root) |
Update fields
Section titled “Update fields”| Field | Type | Description |
|---|---|---|
alt | string | Alt text |
folder | string | null | Move to folder (null for root) |
focalX | number | null | Focal point X (0–100) |
focalY | number | null | Focal point Y (0–100) |
Focal Points
Section titled “Focal Points”Set a focal point on any image in the asset detail view. Image fields in the admin display thumbnails cropped to the focal point via object-position.
Image Optimization
Section titled “Image Optimization”Uploaded images are automatically optimized when rendered on public pages. The CMS includes an on-demand image transformation endpoint powered by Sharp.
How it works
Section titled “How it works”Images in rich text and block content are automatically served as optimized WebP with responsive srcset. No configuration needed — it works out of the box for all local uploads.
The transformation endpoint is at /api/cms/img/[...path]:
/api/cms/img/uploads/photo.jpg?w=800 → 800px wide WebP/api/cms/img/uploads/photo.jpg?w=1024&f=avif → 1024px wide AVIF/api/cms/img/uploads/photo.jpg?q=90 → quality 90| Param | Type | Default | Description |
|---|---|---|---|
w | number | — | Width (snapped to nearest allowed size) |
f | string | webp | Format: webp, avif, jpeg, png |
q | number | 80 | Quality (1–100) |
Transformed images are cached to .cms-cache/img/ and served with immutable cache headers.
Helpers for custom templates
Section titled “Helpers for custom templates”Use cmsImage and cmsSrcset in your own templates:
import { cmsImage, cmsSrcset } from "./cms/core/image";
// Single optimized URLcmsImage("/uploads/photo.jpg", 800);// → /api/cms/img/uploads/photo.jpg?w=800
// Responsive srcsetcmsSrcset("/uploads/photo.jpg", [480, 768, 1024]);// → /api/cms/img/uploads/photo.jpg?w=480 480w, ...Allowed widths
Section titled “Allowed widths”Requested widths are snapped to the nearest allowed size to maximize cache efficiency: 320, 480, 640, 768, 960, 1024, 1280, 1536, 1920.