# 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).