--- name: optimize-images description: Design responsive image pipeline with srcset, modern formats, and lazy loading. Framework-specific implementations. argument-hint: "[--framework next|nuxt|blazor|vanilla] [--format webp|avif|both]" allowed-tools: Read, Glob, Grep, Task, Skill, AskUserQuestion --- # Optimize Images Command Design a responsive image optimization pipeline for web delivery. ## Usage ```bash /cms:optimize-images --framework blazor /cms:optimize-images --framework next --format avif /cms:optimize-images --framework vanilla --format both ``` ## Framework Options - **next**: Next.js Image component - **nuxt**: Nuxt Image module - **blazor**: Blazor component with srcset - **vanilla**: Plain HTML/CSS implementation ## Workflow ### Step 1: Parse Arguments Extract framework and format preferences from command. ### Step 2: Invoke Skills Invoke relevant skills: - `image-optimization` - Responsive patterns - `cdn-media-delivery` - CDN integration ### Step 3: Design Responsive Strategy **Breakpoint Configuration:** ```yaml responsive: breakpoints: mobile: 320 mobile_lg: 480 tablet: 768 desktop: 1024 desktop_lg: 1280 wide: 1920 device_pixel_ratios: [1, 2, 3] sizes_presets: thumbnail: default: 150px card: mobile: 100vw tablet: 50vw desktop: 33vw hero: default: 100vw content: mobile: 100vw tablet: 80vw desktop: 800px formats: priority: [avif, webp, jpg] fallback: jpg ``` ### Step 4: Generate Implementation **Blazor Component:** ```csharp @* ResponsiveImage.razor *@ @foreach (var format in Formats) { } @Alt @code { [Parameter] public string Src { get; set; } [Parameter] public string Alt { get; set; } [Parameter] public int Width { get; set; } [Parameter] public int Height { get; set; } [Parameter] public string Sizes { get; set; } = "100vw"; [Parameter] public bool Lazy { get; set; } = true; [Parameter] public string CssClass { get; set; } [Parameter] public string[] Formats { get; set; } = ["avif", "webp"]; [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } private int[] Widths => [320, 640, 768, 1024, 1280, 1920]; private string FallbackSrc => GetTransformUrl(Src, Width, "jpg"); private string GenerateSrcset(string format) { return string.Join(", ", Widths.Select(w => $"{GetTransformUrl(Src, w, format)} {w}w")); } private string GetTransformUrl(string src, int width, string format) { return $"/media/transform/{GetAssetId(src)}?w={width}&format={format}"; } private string GetMimeType(string format) => format switch { "avif" => "image/avif", "webp" => "image/webp", "jpg" => "image/jpeg", _ => "image/jpeg" }; } ``` **Next.js Implementation:** ```tsx // components/ResponsiveImage.tsx import Image from 'next/image'; interface ResponsiveImageProps { src: string; alt: string; width: number; height: number; sizes?: string; priority?: boolean; className?: string; } export function ResponsiveImage({ src, alt, width, height, sizes = '100vw', priority = false, className, }: ResponsiveImageProps) { return ( {alt} ); } // next.config.js module.exports = { images: { domains: ['cdn.example.com'], deviceSizes: [640, 768, 1024, 1280, 1920], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], formats: ['image/avif', 'image/webp'], minimumCacheTTL: 60 * 60 * 24 * 7, // 7 days loader: 'custom', loaderFile: './lib/imageLoader.ts', }, }; // lib/imageLoader.ts export default function cmsImageLoader({ src, width, quality, }: { src: string; width: number; quality?: number; }) { const q = quality || 85; return `${process.env.CDN_URL}/transform/${src}?w=${width}&q=${q}`; } ``` **Vanilla HTML:** ```html Hero image description ``` ### Step 5: Image Transform API **Transform Service:** ```csharp public class ImageTransformService { public async Task TransformAsync( Guid assetId, ImageTransformOptions options) { var asset = await _mediaRepository.GetAsync(assetId); var cacheKey = GenerateCacheKey(assetId, options); // Check cache first if (await _cache.ExistsAsync(cacheKey)) { return await _cache.GetStreamAsync(cacheKey); } // Get original var original = await _storage.GetAsync(asset.StoragePath); // Transform using ImageSharp using var image = await Image.LoadAsync(original); // Apply focal point aware resize if (options.FocalPoint != null) { image.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(options.Width, options.Height), Mode = ResizeMode.Crop, CenterCoordinates = new PointF( options.FocalPoint.X * image.Width, options.FocalPoint.Y * image.Height) })); } else { image.Mutate(x => x.Resize(options.Width, options.Height)); } // Encode in requested format var output = new MemoryStream(); await EncodeAsync(image, output, options.Format, options.Quality); // Cache result await _cache.SetAsync(cacheKey, output, TimeSpan.FromDays(7)); output.Position = 0; return output; } } public record ImageTransformOptions { public int Width { get; init; } public int? Height { get; init; } public string Format { get; init; } = "webp"; public int Quality { get; init; } = 85; public string Fit { get; init; } = "contain"; public FocalPoint FocalPoint { get; init; } } ``` ### Step 6: Performance Optimizations **Loading Strategies:** ```yaml loading: # Above the fold critical: loading: eager fetchpriority: high decoding: sync # Below the fold lazy: loading: lazy fetchpriority: auto decoding: async # Low priority deferred: loading: lazy fetchpriority: low decoding: async # Placeholder strategies placeholders: blur: true # LQIP (Low Quality Image Placeholder) dominant_color: true skeleton: false ``` **Cache Configuration:** ```yaml caching: # Browser cache browser: max_age: 31536000 # 1 year immutable: true stale_while_revalidate: 86400 # CDN cache cdn: ttl: 604800 # 7 days vary: [Accept] # Format negotiation # Transform cache transform: storage: redis ttl: 604800 max_size: 10GB eviction: lru ``` ## Metrics Track image performance: ```yaml metrics: - largest_contentful_paint - cumulative_layout_shift - time_to_first_byte - cache_hit_ratio - format_distribution - bandwidth_saved ``` ## Related Skills - `image-optimization` - Responsive patterns - `cdn-media-delivery` - CDN configuration - `media-asset-management` - Asset storage