# images > WHAT: ImageCloudinary component with Cloudinary CDN for automatic optimization, quality, and responsive sizing. WHEN: displaying product images, optimizing quality/format, supporting Retina displays, implementing fallbacks. KEYWORDS: ImageCloudinary, Cloudinary, CDN, quality, auto:eco, DPR, crop, gravity, fallbackSource, alt. - Author: João Prado - Repository: guicheffer/devorch-cli - Version: 20260122234748 - Stars: 1 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/guicheffer/devorch-cli - Web: https://mule.run/skillshub/@@guicheffer/devorch-cli~images:20260122234748 --- --- name: images description: "WHAT: ImageCloudinary component with Cloudinary CDN for automatic optimization, quality, and responsive sizing. WHEN: displaying product images, optimizing quality/format, supporting Retina displays, implementing fallbacks. KEYWORDS: ImageCloudinary, Cloudinary, CDN, quality, auto:eco, DPR, crop, gravity, fallbackSource, alt." --- # Image Handling with Cloudinary ## Documentation This skill has comprehensive documentation: - **[Production Examples](./references/examples.md)** - Real-world code examples from the codebase - **[API Reference](./references/api-docs.md)** - Complete API documentation with official links - **[Implementation Patterns](./references/patterns.md)** - Best practices and anti-patterns ## Core Principles **NEVER use `require()` for images.** Using `require()` bundles images into the app, increasing APK/IPA size, preventing CDN optimization, and requiring app redeployment for updates. Always use ImageCloudinary with Cloudinary URLs. **Always use ImageCloudinary for Cloudinary-hosted images.** The ImageCloudinary component automatically applies Cloudinary transformations for format selection (WebP, AVIF), quality optimization, responsive sizing, and Device Pixel Ratio handling. **Always provide alt text for accessibility.** The `alt` prop is required for screen readers. Descriptive alt text improves accessibility and enables visually impaired users to understand image content. **Use auto format and quality for automatic optimization.** Setting `fetchFormat="auto"` and `quality="auto:eco"` enables Cloudinary to serve the most efficient format and quality based on device capabilities and image content. **Why**: Proper image handling ensures fast loading times, optimal quality, responsive designs, and accessibility. Cloudinary provides automatic format selection, quality optimization, and responsive transformations that reduce bandwidth by 30-50% and improve user experience. ## When to Use This Skill Use these patterns when: - Displaying product images, hero images, or thumbnails - Loading images from Cloudinary CDN - Optimizing image quality and format automatically - Supporting high-resolution (Retina) displays - Creating responsive images that adapt to screen size - Implementing fallback images for error handling - Ensuring accessibility with alt text - Cropping or resizing images dynamically - Preloading critical above-the-fold images - Supporting multi-brand image CDNs ## ImageCloudinary Component ### Basic Usage ```typescript import { ImageCloudinary, ImageProxy } from '@libs/cloudinary'; export const ProductImage = ({ imageUrl, alt }) => { return ( ); }; ``` **Why**: ImageCloudinary automatically applies Cloudinary transformations. Format selection (WebP, AVIF, JPEG), quality adjustment, and responsive sizing happen automatically. **Production Example**: `git-resources/shared-mobile-modules/src/modules/store/screens/cart/components/product-item/ProductItem.tsx:122` ### ImageCloudinary Props ```typescript interface ImageCloudinaryProps { // Required width: 'auto' | number; // Image width in pixels or 'auto' for responsive alt: string; // Accessibility label (REQUIRED) source: ImageSourcePropType; // Image source: { uri: string } // Optional optimization fallbackSource?: ImageSourcePropType; // Fallback if main image fails proxy?: ImageProxy; // 'cloudfront' or 'website' // Cloudinary transformations crop?: CloudinaryCropMode; // Default: 'limit' quality?: CloudinaryQuality; // Default: 'auto:eco' fetchFormat?: CloudinaryFetchFormat; // Default: 'auto' dpr?: CloudinaryDPR; // Device pixel ratio gravity?: CloudinaryGravity; // Crop focus point aspectRatio?: number; // Force specific aspect ratio // Standard React Native Image props style?: ImageStyle; resizeMode?: 'cover' | 'contain' | 'stretch' | 'center'; } ``` **Why**: Type-safe props ensure correct usage of Cloudinary transformations and React Native Image properties. ## DO NOT Use require() for Images ### ❌ NEVER Do This ```typescript // ❌ NEVER use require() for images - bundles into app const image = require('./assets/images/my-image.png'); ``` **Why Not**: Bundling images directly increases APK/IPA size, prevents CDN optimization, and requires app redeployment for updates. ### ✅ ALWAYS Use ImageCloudinary ```typescript // ✅ ALWAYS use ImageCloudinary with Cloudinary URLs import { ImageCloudinary } from '@libs/cloudinary'; ``` **Why**: ImageCloudinary serves images from Cloudinary CDN, enabling: - Smaller app bundles (images not bundled) - Dynamic optimization (format, quality, size optimized per device) - Instant updates (change images without app redeployment) - Better performance (global CDN delivery) - Responsive images (automatic device-specific sizing) ### Exceptions (When require() IS Allowed) Only use `require()` for: 1. **System icons** - Very small UI icons that need immediate availability 2. **Splash screen** - Must be available before network connection 3. **Critical fallback images** - Local placeholders for error states ```typescript // ✅ Acceptable use of require() for fallback import placeholderImage from '@assets/images/placeholder.png'; ``` **Why**: These exceptional cases require images before network availability or for graceful error handling. **Production Example**: `git-resources/shared-mobile-modules/src/features/shoppable-product-sections/ingredients/Ingredients.tsx:4` ## Quality Settings ### Quality Hierarchy ```typescript // ✅ Use auto:eco for standard images (best performance) // ✅ Use auto:good for important hero images // ✅ Use auto:best for critical brand images ``` **Why**: `auto:eco` provides the best balance of quality and performance for most images. Cloudinary analyzes image content and adjusts compression accordingly. Use higher quality only for critical images. ### Quality by Context ```typescript const QUALITY_BY_CONTEXT = { thumbnail: 'auto:eco', // Small images, quality less critical productCard: 'auto:eco', // Standard product images hero: 'auto:good', // Important header images brand: 'auto:best', // Logo, brand assets fullscreen: 'auto:best', // Full-screen galleries } as const; ``` **Why**: Different contexts require different quality-performance tradeoffs. Thumbnails benefit from aggressive compression, while brand assets need pristine quality. ## Format Selection ### Auto Format (Recommended) ```typescript // ✅ Use 'auto' for automatic format selection (recommended) ``` **Why**: `fetchFormat="auto"` enables Cloudinary to serve the most efficient format supported by the device (WebP on most modern devices, AVIF on newer ones, JPEG as fallback). This reduces file size by 30-50% without quality loss. ### Specific Formats When Needed ```typescript // ✅ Force PNG for transparency // ✅ Force WebP for modern browsers ``` **Why**: Different image types benefit from different formats. Photos compress well in JPEG/WebP, logos need PNG transparency, icons should be SVG for scalability. ## Device Pixel Ratio (DPR) ### Responsive DPR with useWindowDimensions ```typescript import { useWindowDimensions } from 'react-native'; export const ResponsiveImage = ({ source, alt }) => { const { scale } = useWindowDimensions(); return ( ); }; ``` **Why**: `useWindowDimensions().scale` provides the device pixel ratio (1x for standard, 2x for Retina, 3x for high-res). Cloudinary multiplies image dimensions by DPR to serve appropriately sized images for each display. ### DPR Values ```typescript // Common device pixel ratios: // - Standard displays: 1.0 // - Retina displays: 2.0 // - High-resolution displays: 3.0 type CloudinaryDPR = '1.0' | '1.5' | '2.0' | '3.0' | 'auto'; // Example usage: const { scale } = useWindowDimensions(); // Manual DPR based on device // Automatic DPR (Cloudinary detects) ``` **Why**: Matching DPR to device capabilities ensures sharp images without wasting bandwidth. A 2x display needs 2x resolution, but serving 3x images wastes 50% of bandwidth. **Production Example**: `git-resources/shared-mobile-modules/src/libs/cloudinary/ImageCloudinary.tsx:61` ## Crop Modes ### Common Crop Modes ```typescript // 'limit' - Resize within boundaries, maintain aspect ratio (default) // 'fill' - Fill exact dimensions, may crop // 'fit' - Fit within boundaries, add padding if needed // 'thumb' - Generate thumbnail with smart cropping ``` **Why**: Different crop modes serve different use cases. `limit` preserves quality, `fill` ensures consistent dimensions, `thumb` creates smart thumbnails focusing on important content. ### Crop Mode by Context ```typescript const CROP_BY_CONTEXT = { productCard: 'limit', // Preserve product proportions avatar: 'fill', // Circular avatars need exact dimensions thumbnail: 'thumb', // Smart crop for small previews hero: 'fill', // Hero images fill container logo: 'fit', // Logos need padding, no distortion } as const; ``` **Why**: Selecting the right crop mode prevents unwanted distortion and ensures images display correctly in different contexts. ## Gravity (Crop Focus) ### Smart Cropping with Gravity ```typescript // 'auto' - Smart crop focusing on important content // 'face' - Focus on faces // 'center' - Center crop (default) // Position-based gravity ``` **Why**: Gravity controls which part of the image to preserve during cropping. `auto` uses AI to detect important content (faces, objects), ensuring smart crops that don't cut off critical elements. ## Responsive Image Sizing ### Auto Width with Responsive Height ```typescript import { useWindowDimensions } from 'react-native'; export const ResponsiveHeroImage = ({ imageUrl }) => { const { height, scale } = useWindowDimensions(); return ( ); }; ``` **Why**: Setting `width="auto"` makes images responsive to container width, while calculating `height` as a percentage of screen height ensures consistent proportions across devices. ### Fixed Width with Dynamic Aspect Ratio ```typescript import { DeviceDimensionsUtils } from '@libs/utils'; // Device-specific aspect ratio const ASPECT_RATIO = DeviceDimensionsUtils.getDeviceValue( 16 / 9, // Small devices - wider ratio 3 / 2, // Medium devices - balanced 5 / 4 // Large devices - taller ratio ); export const ProductImage = ({ imageUrl }) => { const IMAGE_WIDTH = 300; const IMAGE_HEIGHT = IMAGE_WIDTH / ASPECT_RATIO; return ( ); }; ``` **Why**: Device-specific aspect ratios ensure images look proportional on different screen sizes. Small devices use wider ratios (landscape-friendly), large devices use taller ratios (more vertical content visible). **Production Example**: `git-resources/shared-mobile-modules/src/libs/cloudinary/ImageCloudinary.tsx:42` ### Percentage-Based Sizing ```typescript import { useWindowDimensions } from 'react-native'; export const FlexibleImage = ({ imageUrl, aspectRatio = 16 / 9 }) => { const { width } = useWindowDimensions(); const imageWidth = width * 0.9; // 90% of screen width const imageHeight = imageWidth / aspectRatio; return ( ); }; ``` **Why**: Percentage-based sizing adapts images to any screen size. 90% width leaves comfortable margins, while maintaining aspect ratio prevents distortion. ## Image Proxies ### Image Proxy Types ```typescript export enum ImageProxy { cloudfront = 'cloudfront', // CloudFront CDN (faster delivery) website = 'website', // Direct website URL } // Use CloudFront for production assets // Use website proxy for user-uploaded content ``` **Why**: Image proxies determine how Cloudinary fetches the original image. CloudFront provides global CDN distribution for faster loading. Website proxy fetches directly from origin URLs. **Production Example**: `git-resources/shared-mobile-modules/src/modules/store/screens/cart/components/product-item/ProductItem.tsx:129` ## Fallback Images ### Error Handling with Fallbacks ```typescript import placeholderImage from '@assets/images/placeholder.png'; export const ProductImageWithFallback = ({ imageUrl, productName }) => { return ( ); }; ``` **Why**: Fallback images prevent broken image icons when network requests fail or URLs are invalid. Provides graceful degradation experience. **Production Example**: `git-resources/shared-mobile-modules/src/features/shoppable-product-sections/ingredients/Ingredients.tsx:106` ### Implementing Error Handling ```typescript import { useState } from 'react'; export const ImageWithFallback = ({ imageUrl, fallbackUrl, alt }) => { const [hasError, setHasError] = useState(false); const currentSource = hasError && fallbackUrl ? { uri: fallbackUrl } : { uri: imageUrl }; return ( setHasError(true)} {...props} /> ); }; ``` **Why**: Tracking error state enables multiple fallback attempts or displaying custom error UI instead of broken images. **Production Example**: `git-resources/shared-mobile-modules/src/libs/cloudinary/ImageCloudinary.tsx:50` ## Accessibility ### Alt Text Requirements ```typescript // ✅ Always provide descriptive alt text // ✅ Alt text for decorative images can be empty // ❌ Never omit alt prop ``` **Why**: Alt text is required for screen readers to describe images to visually impaired users. Descriptive alt text improves accessibility. Empty alt (`alt=""`) marks decorative images that should be skipped by screen readers. ### Writing Good Alt Text ```typescript // ✅ Good alt text: Descriptive and concise // ❌ Bad alt text: Too vague // ❌ Bad alt text: Redundant words // ✅ Good alt text for functional images ``` **Why**: Good alt text describes image content concisely without redundant phrases like "image of" or "picture of". For functional images (buttons, icons), describe the action, not the visual. ## Performance Best Practices ### Calculate Exact Size Needed ```typescript // ✅ Calculate exact size needed const { width } = useWindowDimensions(); const cardWidth = (width - 48) / 2; // 2 columns with padding // ❌ Don't request oversized images ``` **Why**: Requesting images at the exact size needed reduces bandwidth usage and loading time. Downloading 1000px images to display at 150px wastes 95% of bandwidth. ### Preloading Critical Images ```typescript import { Image } from 'react-native'; import { useEffect } from 'react'; export const usePreloadImages = (imageUrls: string[]) => { useEffect(() => { // Preload images into cache imageUrls.forEach((url) => { Image.prefetch(url); }); }, [imageUrls]); }; // Usage export const ProductScreen = () => { usePreloadImages([ heroImageUrl, productImage1Url, productImage2Url, ]); return ; }; ``` **Why**: Preloading critical images prevents loading spinners for important above-the-fold content, improving perceived performance. ## Common Mistakes to Avoid ❌ **Don't use require() for images**: ```typescript // ❌ Bundles into app, increases size const image = require('./assets/images/product.png'); ``` **Why**: Bundling images directly increases APK/IPA size, prevents CDN optimization, and requires app redeployment for updates. ✅ **Do use ImageCloudinary with Cloudinary URLs**: ```typescript // ✅ CDN delivery, automatic optimization ``` **Why**: Cloudinary CDN provides automatic optimization, format selection, and responsive sizing without increasing app bundle size. ❌ **Don't omit alt text**: ```typescript // ❌ Accessibility violation ``` **Why**: Screen readers cannot describe images without alt text, creating accessibility barriers for visually impaired users. ✅ **Do always provide alt text**: ```typescript // ✅ Accessible image ``` **Why**: Alt text enables screen readers to describe images, improving accessibility for all users. ❌ **Don't request oversized images**: ```typescript // ❌ Wastes bandwidth - displaying 150px but loading 1000px ``` **Why**: Loading large images and scaling them down wastes bandwidth (95% waste) and slows loading times. ✅ **Do request exact size needed**: ```typescript // ✅ Efficient - loads exact size ``` **Why**: Requesting exact dimensions reduces file size and improves performance dramatically. ❌ **Don't ignore device pixel ratio**: ```typescript // ❌ Blurry on high-resolution displays ``` **Why**: Fixed 1x DPR creates blurry images on Retina and high-resolution displays. ✅ **Do use device scale for DPR**: ```typescript // ✅ Sharp on all displays const { scale } = useWindowDimensions(); ``` **Why**: Matching DPR to device scale ensures sharp images on all display types (standard, Retina, high-res). ❌ **Don't forget fallback images**: ```typescript // ❌ Shows broken image icon on error ``` **Why**: Network errors or invalid URLs show broken image icons, degrading user experience. ✅ **Do provide fallback images**: ```typescript // ✅ Graceful degradation ``` **Why**: Fallback images provide graceful degradation when primary images fail to load. ## Quick Reference **Basic ImageCloudinary**: ```typescript import { ImageCloudinary, ImageProxy } from '@libs/cloudinary'; ``` **Responsive image with DPR**: ```typescript const { scale } = useWindowDimensions(); ``` **Image with fallback**: ```typescript import placeholderImage from '@assets/images/placeholder.png'; ``` **Auto-width hero image**: ```typescript const { height, scale } = useWindowDimensions(); ``` **Thumbnail with smart crop**: ```typescript ``` **Quality by context**: ```typescript // Thumbnails: auto:eco // Product cards: auto:eco // Hero images: auto:good // Brand assets: auto:best ``` **Crop modes**: ```typescript crop="limit" // Preserve aspect ratio (default) crop="fill" // Fill exact dimensions (crops) crop="fit" // Fit with padding crop="thumb" // Smart thumbnail ``` **Key Libraries:** - react-native 0.76+ - @zest/react-native 1.5.3 - Cloudinary CDN with multi-brand support **Brand-Specific CDN URLs:** - yourcompany → https://media.yourcompany.com - greenchef → https://media.greenchef.com - everyplate → https://media.everyplate.com - factor → https://media.factor75.com For production examples, see [references/examples.md](references/examples.md).