visuellverstehen/statamic-picturesque
Statamic addon that generates responsive, optimized picture elements from your assets. It handles srcset, multiple formats like WebP and AVIF, and lazy loading out of the box, so you can drop flexible, performance-friendly images into your Antlers templates with a single tag.
Picturesque turns a Statamic asset (or a set of them) into responsive <picture>/<img> markup with Glide-generated derivatives — srcsets, per-breakpoint widths, and modern formats — without hand-writing {{ glide:generate }} chains.
composer require visuellverstehen/statamic-picturesque
php artisan vendor:publish --tag=picturesque-config
config/picturesque.php first — this is the file you will spend 90% of your time in. It defines the named sources (breakpoints + width/height/format rules), the default source set, the default formats, and cache behaviour. Treat it as your design-system ↔ image pipeline contract.{{ glide }} / raw <img> with the tag:
{{ picturesque :src="hero_image" sizes="100vw" }}
{{ picturesque :src="hero_image" sources="sm,md,lg" sizes="(min-width: 1024px) 50vw, 100vw" }}
Comma-separated sources is restored in 2.2.0 — before that you were forced into YAML-array syntax in the template, which most people found noisy.First real use case: a hero/banner partial that takes an asset field and renders a <picture> with AVIF/WebP + JPEG fallback and a srcset driven by your config breakpoints.
Named sources as your design tokens. Define the breakpoints once in config/picturesque.php (sm, md, lg, xl, each with a width and optional height/ratio), then reference them by name everywhere. This keeps templates readable and lets you change a width in one place instead of grepping through Antlers files.
Comma-separated source lists (2.2.0). The pragmatic default for templates:
{{ picturesque :src="image" sources="sm,md,lg,xl" sizes="100vw" }}
Use the array/binding form (:sources="['sm','md']") only when the list is computed — e.g. from a Bard set, a fieldset toggle, or a layout partial's parameter. Both forms should be interchangeable, so pick one convention per project and lint for it.
Wrap it in a partial/component. The tag has a lot of optional surface area (alt, class, sizes, formats, placeholder, loading, fetchpriority). Create resources/views/components/picturesque.antlers.html that takes src, sources, sizes, class, alt, priority and forwards them. This is the single biggest maintainability win and makes swapping the package later survivable.
Format strategy. Enable webp (and avif if your Glide/imagemagick build supports it) in the config rather than per-call, and let the tag emit <source type="..."> before the fallback <img>. Keep the fallback format as jpg/png — animated GIFs and SVGs should bypass the tag entirely.
Layout-driven sizes. Always pass sizes that mirrors the actual CSS. A missing sizes makes browsers assume 100vw, so a 400px-wide card downloads the 1920px derivative. Pair each breakpoint source with the media query that matches it, and put the mapping in a comment above the partial.
Art-directed and per-context images. For Bard/replicator sets, drive sources from the set config (e.g. sources="{set:image_size}" where the value is sm,md or lg,xl). This is exactly the pattern the restored comma syntax makes pleasant — a field value can be passed straight through as a string.
Focal points and Glide parity. Picturesque sits on top of Glide, so use Statamic's focal point field and pass through your normal Glide params (:glide="true") when you need cropping (fit, crop, brightness). Keep custom params in a config array rather than inline so caches stay consistent.
Static/edge caching. Generate derivatives at deploy (or via a warm-up command hitting your top N pages) rather than on first anonymous request. If you use the static cache, remember the generated markup is frozen — clear both Picturesque's derivative cache and the static cache when breakpoints change.
sources="sm, md, lg" may not trim as you expect (and "sm,,lg" definitely won't). Write it without spaces, sources="sm,md,lg", and prefer the binding form if the list is dynamic.sources accepts both a comma string and an array, a value like "1" or a single name behaves identically — but a mistyped array (e.g. sources="[sm,md]" in a non-:, non-YAML context) silently degrades to one weird source name. If the output has no srcset, dump the resolved sources before touching anything else.config/picturesque.php usually just yields fewer <source> entries — no exception. Keep the config and template names in sync, and add a test/smoke check that asserts the expected number of srcset candidates.sizes is not optional in practice. Omit it and you ship oversized images to every phone. If you can't compute sizes, at least pass a conservative single value — it's better than nothing.srcset logic; for anything more exotic (CDN-specific URL signing, per-tenant breakpoints), wrap the tag in your own Antlers tag or partial rather than forking the config.sources continue to work. No migration required, but it is worth normalising templates to the comma form or the array form so the codebase doesn't drift into both.How can I help you explore Laravel packages today?