Use when implementing responsive images, format conversion, focal point cropping, or image processing pipelines. Covers srcset generation, WebP/AVIF conversion, lazy loading, and image transformation APIs for headless CMS.
Implements responsive images with srcset generation and modern format conversion (WebP/AVIF). Use when building image processing pipelines, optimizing performance, or handling focal point cropping for headless CMS.
/plugin marketplace add melodic-software/claude-code-plugins/plugin install content-management-system@melodic-softwareThis skill is limited to using the following tools:
Guidance for implementing responsive images, format optimization, and image processing pipelines for headless CMS.
<!-- Basic srcset with width descriptors -->
<img
src="/images/hero.jpg"
srcset="
/images/hero-400w.jpg 400w,
/images/hero-800w.jpg 800w,
/images/hero-1200w.jpg 1200w,
/images/hero-1600w.jpg 1600w
"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
alt="Hero image"
>
<!-- Srcset with pixel density -->
<img
src="/images/logo.png"
srcset="
/images/logo.png 1x,
/images/logo@2x.png 2x,
/images/logo@3x.png 3x
"
alt="Logo"
>
<picture>
<!-- Mobile: Square crop -->
<source
media="(max-width: 600px)"
srcset="/images/hero-mobile.webp"
type="image/webp"
>
<source
media="(max-width: 600px)"
srcset="/images/hero-mobile.jpg"
>
<!-- Desktop: Wide crop -->
<source
srcset="/images/hero-desktop.webp"
type="image/webp"
>
<!-- Fallback -->
<img src="/images/hero-desktop.jpg" alt="Hero">
</picture>
public class ImageProcessingService
{
public async Task<Stream> ProcessAsync(
Stream source,
ImageProcessingOptions options)
{
using var image = await Image.LoadAsync(source);
// Resize
if (options.Width.HasValue || options.Height.HasValue)
{
var resizeOptions = new ResizeOptions
{
Size = new Size(
options.Width ?? 0,
options.Height ?? 0),
Mode = options.ResizeMode,
Position = options.FocalPoint != null
? CalculateAnchor(options.FocalPoint, image.Size)
: AnchorPositionMode.Center
};
image.Mutate(x => x.Resize(resizeOptions));
}
// Apply effects
if (options.Blur > 0)
{
image.Mutate(x => x.GaussianBlur(options.Blur));
}
if (options.Grayscale)
{
image.Mutate(x => x.Grayscale());
}
// Encode to target format
var outputStream = new MemoryStream();
await EncodeAsync(image, outputStream, options);
outputStream.Position = 0;
return outputStream;
}
private async Task EncodeAsync(
Image image,
Stream output,
ImageProcessingOptions options)
{
switch (options.Format)
{
case ImageFormat.WebP:
await image.SaveAsWebpAsync(output, new WebpEncoder
{
Quality = options.Quality,
Method = WebpEncodingMethod.BestQuality
});
break;
case ImageFormat.Avif:
await image.SaveAsAvifAsync(output, new AvifEncoder
{
Quality = options.Quality
});
break;
case ImageFormat.Jpeg:
await image.SaveAsJpegAsync(output, new JpegEncoder
{
Quality = options.Quality,
ColorType = JpegEncodingColor.YCbCrRatio420
});
break;
case ImageFormat.Png:
await image.SaveAsPngAsync(output, new PngEncoder
{
CompressionLevel = PngCompressionLevel.BestCompression
});
break;
}
}
}
public class ImageProcessingOptions
{
public int? Width { get; set; }
public int? Height { get; set; }
public ResizeMode ResizeMode { get; set; } = ResizeMode.Max;
public FocalPoint? FocalPoint { get; set; }
public ImageFormat Format { get; set; } = ImageFormat.WebP;
public int Quality { get; set; } = 80;
public float Blur { get; set; }
public bool Grayscale { get; set; }
}
public class FocalPoint
{
public float X { get; set; } // 0-1, left to right
public float Y { get; set; } // 0-1, top to bottom
}
public enum ImageFormat
{
Jpeg,
Png,
WebP,
Avif,
Gif
}
public class ImagePresets
{
public static readonly Dictionary<string, ImageProcessingOptions> Presets = new()
{
["thumbnail"] = new()
{
Width = 150,
Height = 150,
ResizeMode = ResizeMode.Crop,
Format = ImageFormat.WebP,
Quality = 75
},
["card"] = new()
{
Width = 400,
Height = 300,
ResizeMode = ResizeMode.Crop,
Format = ImageFormat.WebP,
Quality = 80
},
["hero"] = new()
{
Width = 1920,
Height = 800,
ResizeMode = ResizeMode.Crop,
Format = ImageFormat.WebP,
Quality = 85
},
["og-image"] = new()
{
Width = 1200,
Height = 630,
ResizeMode = ResizeMode.Crop,
Format = ImageFormat.Jpeg,
Quality = 90
},
["blur-placeholder"] = new()
{
Width = 20,
Height = 20,
Format = ImageFormat.Jpeg,
Quality = 30,
Blur = 5
}
};
}
public class FocalPointService
{
public AnchorPositionMode CalculateAnchor(
FocalPoint focal,
Size imageSize,
Size targetSize)
{
// Calculate which part of image will be cropped
var imageAspect = (float)imageSize.Width / imageSize.Height;
var targetAspect = (float)targetSize.Width / targetSize.Height;
if (Math.Abs(imageAspect - targetAspect) < 0.01f)
{
return AnchorPositionMode.Center;
}
// Determine crop direction
var cropHorizontal = imageAspect > targetAspect;
if (cropHorizontal)
{
// Cropping sides, use X focal point
return focal.X switch
{
< 0.33f => AnchorPositionMode.Left,
> 0.66f => AnchorPositionMode.Right,
_ => AnchorPositionMode.Center
};
}
else
{
// Cropping top/bottom, use Y focal point
return focal.Y switch
{
< 0.33f => AnchorPositionMode.Top,
> 0.66f => AnchorPositionMode.Bottom,
_ => AnchorPositionMode.Center
};
}
}
}
public class MediaItem
{
public Guid Id { get; set; }
public string FileName { get; set; } = string.Empty;
// Focal point for smart cropping
public FocalPoint? FocalPoint { get; set; }
}
// Set via API
PATCH /api/media/{id}
{
"focalPoint": { "x": 0.3, "y": 0.2 }
}
# Base URL
https://cdn.example.com/media/hero.jpg
# With transformations
https://cdn.example.com/media/hero.jpg?w=800&h=600&fit=crop
https://cdn.example.com/media/hero.jpg?w=400&format=webp&q=80
https://cdn.example.com/media/hero.jpg?preset=thumbnail
[Route("media/{*path}")]
public class ImageTransformController : ControllerBase
{
[HttpGet]
[ResponseCache(Duration = 31536000, VaryByQueryKeys = new[] { "*" })]
public async Task<IActionResult> GetTransformed(
string path,
[FromQuery] int? w,
[FromQuery] int? h,
[FromQuery] string? format,
[FromQuery] int? q,
[FromQuery] string? fit,
[FromQuery] string? preset)
{
// Get original image
var original = await _mediaService.GetStreamAsync(path);
if (original == null) return NotFound();
// Build options from query or preset
var options = preset != null
? ImagePresets.Presets.GetValueOrDefault(preset) ?? new()
: new ImageProcessingOptions
{
Width = w,
Height = h,
Format = ParseFormat(format),
Quality = q ?? 80,
ResizeMode = ParseFit(fit)
};
// Process image
var processed = await _imageProcessor.ProcessAsync(original, options);
return File(processed, GetMimeType(options.Format));
}
}
public class ResponsiveImageService
{
private readonly int[] _defaultWidths = { 320, 640, 960, 1280, 1920 };
public ResponsiveImageData GenerateSrcset(
MediaItem media,
ResponsiveImageOptions? options = null)
{
options ??= new ResponsiveImageOptions();
var widths = options.Widths ?? _defaultWidths;
var srcset = widths
.Where(w => w <= (media.Metadata.Width ?? int.MaxValue))
.Select(w => new SrcsetEntry
{
Url = BuildTransformUrl(media, w, options.Format),
Width = w
})
.ToList();
return new ResponsiveImageData
{
Src = BuildTransformUrl(media, options.DefaultWidth, options.Format),
Srcset = srcset,
Sizes = options.Sizes ?? "(max-width: 1200px) 100vw, 1200px",
Alt = media.Metadata.Alt ?? "",
Width = media.Metadata.Width,
Height = media.Metadata.Height,
BlurDataUrl = options.IncludeBlurPlaceholder
? BuildTransformUrl(media, 20, ImageFormat.Jpeg, blur: 5)
: null
};
}
private string BuildTransformUrl(
MediaItem media,
int width,
ImageFormat format,
int? blur = null)
{
var query = $"?w={width}&format={format.ToString().ToLower()}";
if (blur.HasValue) query += $"&blur={blur}";
return $"{_cdnBaseUrl}/media/{media.StoragePath}{query}";
}
}
public class ResponsiveImageData
{
public string Src { get; set; } = string.Empty;
public List<SrcsetEntry> Srcset { get; set; } = new();
public string Sizes { get; set; } = string.Empty;
public string Alt { get; set; } = string.Empty;
public int? Width { get; set; }
public int? Height { get; set; }
public string? BlurDataUrl { get; set; }
}
public class SrcsetEntry
{
public string Url { get; set; } = string.Empty;
public int Width { get; set; }
public override string ToString() => $"{Url} {Width}w";
}
public class BlurHashService
{
public string GenerateBlurHash(Image image, int componentsX = 4, int componentsY = 3)
{
// Resize to small dimensions for hash calculation
using var small = image.Clone(x => x.Resize(32, 32));
// Calculate blur hash
var pixels = new Pixel[32, 32];
for (var y = 0; y < 32; y++)
{
for (var x = 0; x < 32; x++)
{
var pixel = small[x, y];
pixels[x, y] = new Pixel(pixel.R, pixel.G, pixel.B);
}
}
return BlurHash.Encode(pixels, componentsX, componentsY);
}
}
| Strategy | Size | Quality | Use Case |
|---|---|---|---|
| Blur hash | ~30 chars | Good | Inline in HTML |
| Tiny JPEG | ~500 bytes | Medium | Data URL |
| Dominant color | 7 chars | Simple | CSS background |
| SVG trace | ~2KB | Good | Artistic sites |
<!-- Native lazy loading -->
<img
src="/images/photo.jpg"
loading="lazy"
decoding="async"
alt="Photo"
>
<!-- With blur placeholder -->
<div class="image-container" style="background: url(data:image/jpeg;base64,...)">
<img
src="/images/photo.jpg"
loading="lazy"
onload="this.parentElement.style.background = 'none'"
alt="Photo"
>
</div>
public ImageFormat SelectOptimalFormat(string acceptHeader, ImageFormat preferred)
{
if (acceptHeader.Contains("image/avif"))
return ImageFormat.Avif;
if (acceptHeader.Contains("image/webp"))
return ImageFormat.WebP;
return preferred;
}
{
"data": {
"id": "media-123",
"original": {
"url": "https://cdn.example.com/media/original/hero.jpg",
"width": 3840,
"height": 2160,
"mimeType": "image/jpeg",
"sizeBytes": 2456789
},
"responsive": {
"src": "https://cdn.example.com/media/hero.jpg?w=1280&format=webp",
"srcset": "https://cdn.example.com/media/hero.jpg?w=320&format=webp 320w, ...",
"sizes": "(max-width: 1200px) 100vw, 1200px"
},
"placeholder": {
"blurHash": "LEHV6nWB2yk8pyo0adR*.7kCMdnj",
"dataUrl": "data:image/jpeg;base64,/9j/4AAQ..."
},
"focalPoint": { "x": 0.5, "y": 0.3 }
}
}
media-asset-management - Media library and uploadcdn-media-delivery - CDN integration and cachingheadless-api-design - Image API endpointsCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.