DOMAIN:VISUAL_PRODUCTION:DELIVERY_SPECS¶
OWNER: felice
UPDATED: 2026-03-24
SCOPE: Standard delivery specifications per context — web, mobile, social, App Store, email, video
AGENTS: felice (primary), martijn/valentin (iOS assets), floris/floor (frontend), karel (CDN)
PARENT: Visual Production
SPECS:WEB_IMAGES¶
HERO_IMAGES¶
RESOLUTION: 1920x1080 minimum, 2400x1350 for retina
FORMAT: AVIF (primary) + WebP (fallback) + JPEG (legacy)
QUALITY: AVIF 60, WebP 80, JPEG 80
MAX_SIZE: 500 KB (AVIF), 800 KB (WebP), 1.2 MB (JPEG)
RESPONSIVE: generate at 400w, 800w, 1200w, 1600w, 2400w
LOADING: fetchpriority="high", NO lazy loading
CLS: always set width and height attributes
<picture>
<source type="image/avif"
srcset="/img/hero-400.avif 400w, /img/hero-800.avif 800w, /img/hero-1200.avif 1200w,
/img/hero-1600.avif 1600w, /img/hero-2400.avif 2400w"
sizes="100vw">
<source type="image/webp"
srcset="/img/hero-400.webp 400w, /img/hero-800.webp 800w, /img/hero-1200.webp 1200w,
/img/hero-1600.webp 1600w, /img/hero-2400.webp 2400w"
sizes="100vw">
<img
src="/img/hero-1200.jpg"
alt="Platform dashboard showing real-time analytics with charts and data tables"
width="1920"
height="1080"
fetchpriority="high"
decoding="auto"
>
</picture>
CONTENT_IMAGES¶
RESOLUTION: 1200x800 max for body content
FORMAT: AVIF + WebP + JPEG
QUALITY: AVIF 60, WebP 80, JPEG 80
MAX_SIZE: 300 KB (AVIF), 500 KB (WebP), 800 KB (JPEG)
RESPONSIVE: generate at 400w, 800w, 1200w
LOADING: loading="lazy" + decoding="async"
<picture>
<source type="image/avif"
srcset="/img/feature-400.avif 400w, /img/feature-800.avif 800w, /img/feature-1200.avif 1200w"
sizes="(max-width: 768px) 100vw, 50vw">
<source type="image/webp"
srcset="/img/feature-400.webp 400w, /img/feature-800.webp 800w, /img/feature-1200.webp 1200w"
sizes="(max-width: 768px) 100vw, 50vw">
<img
src="/img/feature-800.jpg"
alt="Feature description"
width="800"
height="600"
loading="lazy"
decoding="async"
>
</picture>
THUMBNAILS¶
RESOLUTION: 400x300 (4:3) or 400x225 (16:9)
FORMAT: WebP (primary) + JPEG (fallback)
QUALITY: WebP 75, JPEG 75
MAX_SIZE: 50 KB
RESPONSIVE: single size (400w sufficient)
LOADING: loading="lazy"
ICONS_AND_LOGOS¶
FORMAT: SVG (always)
OPTIMIZATION: SVGO processed, no width/height (use viewBox)
FALLBACK: PNG at 2x target size for email/legacy contexts
MAX_SIZE: 5 KB per icon, 15 KB per logo
SPECS:MOBILE_IOS¶
ASSET_CATALOG_SIZES¶
iOS requires assets at 1x, 2x, and 3x scale:
| Scale | Multiplier | Example (44pt icon) |
|---|---|---|
| @1x | 1x | 44x44 px |
| @2x | 2x | 88x88 px |
| @3x | 3x | 132x132 px |
APP_ICONS¶
| Size | Usage |
|---|---|
| 1024x1024 | App Store listing |
| 180x180 | iPhone @3x (60pt) |
| 120x120 | iPhone @2x (60pt) |
| 167x167 | iPad Pro @2x (83.5pt) |
| 152x152 | iPad @2x (76pt) |
| 80x80 | Spotlight @2x |
| 120x120 | Spotlight @3x |
| 58x58 | Settings @2x |
| 87x87 | Settings @3x |
FORMAT: PNG, no transparency, no rounded corners (iOS adds them)
RULE: provide 1024x1024 master — Xcode generates all sizes from it
RULE: no alpha channel — App Store rejects icons with transparency
LAUNCH_SCREEN_IMAGES¶
| Device | Portrait | Landscape |
|---|---|---|
| iPhone 15 Pro Max | 1290x2796 | 2796x1290 |
| iPhone 15 Pro | 1179x2556 | 2556x1179 |
| iPhone 15 | 1170x2532 | 2532x1170 |
| iPhone SE (3rd) | 750x1334 | 1334x750 |
| iPad Pro 12.9" | 2048x2732 | 2732x2048 |
| iPad Pro 11" | 1668x2388 | 2388x1668 |
| iPad Air | 1640x2360 | 2360x1640 |
| iPad mini | 1488x2266 | 2266x1488 |
FORMAT: PNG
RULE: use auto-layout launch screens (Storyboard) instead of static images when possible
GENERAL_IOS_ASSETS¶
FORMAT: PNG for raster, PDF for vector (Xcode renders at build time)
NAMING: asset-name@2x.png, asset-name@3x.png
RULE: always provide @2x and @3x — @1x is obsolete (no 1x devices in active use)
RULE: use PDF for simple icons/illustrations — single file, auto-scaled
ASSET_CATALOG_JSON (Contents.json):
{
"images": [
{ "filename": "icon@2x.png", "idiom": "universal", "scale": "2x" },
{ "filename": "icon@3x.png", "idiom": "universal", "scale": "3x" }
],
"info": { "author": "xcode", "version": 1 }
}
SPECS:MOBILE_ANDROID¶
DENSITY_BUCKETS¶
| Density | Scale | DPI | Example (48dp icon) |
|---|---|---|---|
| mdpi | 1x | 160 | 48x48 px |
| hdpi | 1.5x | 240 | 72x72 px |
| xhdpi | 2x | 320 | 96x96 px |
| xxhdpi | 3x | 480 | 144x144 px |
| xxxhdpi | 4x | 640 | 192x192 px |
DIRECTORY_STRUCTURE¶
res/
├── drawable-mdpi/ -- 1x
├── drawable-hdpi/ -- 1.5x
├── drawable-xhdpi/ -- 2x
├── drawable-xxhdpi/ -- 3x
├── drawable-xxxhdpi/ -- 4x
└── drawable/ -- XML drawables (vector)
APP_ICONS¶
ADAPTIVE_ICON (Android 8+):
- foreground: 108x108 dp (432x432 px at xxxhdpi)
- background: 108x108 dp (solid color or image)
- safe zone: centered 72x72 dp circle (288x288 px at xxxhdpi)
- system masks the icon shape (circle, squircle, rounded square)
LEGACY_ICON:
| Density | Size |
|---------|------|
| mdpi | 48x48 |
| hdpi | 72x72 |
| xhdpi | 96x96 |
| xxhdpi | 144x144 |
| xxxhdpi | 192x192 |
Play Store: 512x512 PNG (foreground on transparent background)
FORMAT: PNG for raster, XML vector drawable for icons
RULE: prefer vector drawables for icons — single file, all densities
RULE: always provide adaptive icon assets (foreground + background layers)
SPECS:SOCIAL_MEDIA¶
DIMENSIONS_PER_PLATFORM¶
INSTAGRAM:
| Type | Dimensions | Aspect Ratio | Max Size |
|------|-----------|--------------|----------|
| Feed post (square) | 1080x1080 | 1:1 | 30 MB |
| Feed post (portrait) | 1080x1350 | 4:5 | 30 MB |
| Feed post (landscape) | 1080x566 | 1.91:1 | 30 MB |
| Story/Reel | 1080x1920 | 9:16 | 30 MB |
| Profile picture | 320x320 | 1:1 | 10 MB |
LINKEDIN:
| Type | Dimensions | Aspect Ratio | Max Size |
|------|-----------|--------------|----------|
| Feed image | 1200x627 | 1.91:1 | 10 MB |
| Profile image | 400x400 | 1:1 | 8 MB |
| Company page cover | 1128x191 | ~5.9:1 | 8 MB |
| Article cover | 1200x644 | 1.86:1 | 10 MB |
FACEBOOK:
| Type | Dimensions | Aspect Ratio | Max Size |
|------|-----------|--------------|----------|
| Feed image | 1200x630 | 1.91:1 | 30 MB |
| Profile image | 170x170 | 1:1 | 10 MB |
| Cover photo | 820x312 | 2.63:1 | 10 MB |
| Event cover | 1920x1005 | 1.91:1 | 10 MB |
X (TWITTER):
| Type | Dimensions | Aspect Ratio | Max Size |
|------|-----------|--------------|----------|
| Feed image | 1200x675 | 16:9 | 5 MB |
| Profile image | 400x400 | 1:1 | 2 MB |
| Header image | 1500x500 | 3:1 | 5 MB |
| Card image | 800x418 | 1.91:1 | 5 MB |
RULE: always export at exact platform dimensions — platforms re-compress uploaded images
RULE: use JPEG or PNG for social uploads (platforms don't accept WebP/AVIF)
RULE: JPEG quality 90+ for social — platforms apply their own compression
OPEN_GRAPH_META¶
<meta property="og:image" content="https://example.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:alt" content="Descriptive text for the image">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://example.com/twitter-card.jpg">
RULE: OG image must be 1200x630 for optimal display across all platforms
RULE: image must be accessible via public URL (no auth, no CDN restrictions)
RULE: JPEG format for OG images — widest compatibility
SPECS:APP_STORE_SCREENSHOTS¶
APPLE_APP_STORE¶
REQUIRED_SIZES (at least one per category):
| Device | Dimensions | Required |
|---|---|---|
| iPhone 6.9" (15 Pro Max) | 1320x2868 or 2868x1320 | yes |
| iPhone 6.7" (15 Plus) | 1290x2796 or 2796x1290 | yes |
| iPhone 6.5" (older Plus/Max) | 1284x2778 or 2778x1284 | optional |
| iPhone 5.5" (SE-compatible) | 1242x2208 or 2208x1242 | yes |
| iPad Pro 12.9" (6th gen) | 2048x2732 or 2732x2048 | yes (if iPad app) |
| iPad Pro 11" | 1668x2388 or 2388x1668 | optional |
FORMAT: PNG or JPEG
COUNT: 1-10 screenshots per localization
RULE: first 3 screenshots are most important — they show in search results
RULE: screenshots can include device frames, captions, and marketing text
RULE: no alpha channel, no rounded corners (Apple adds them)
GOOGLE_PLAY_STORE¶
| Asset | Dimensions | Format |
|---|---|---|
| Phone screenshot | min 320px, max 3840px, 16:9 or 9:16 | JPEG or PNG |
| 7" tablet screenshot | same as phone | JPEG or PNG |
| 10" tablet screenshot | same as phone | JPEG or PNG |
| Feature graphic | 1024x500 | JPEG or PNG |
| Promo video | YouTube URL | N/A |
COUNT: 2-8 screenshots per device type
RULE: feature graphic is mandatory — used as hero on Play Store listing
RULE: first screenshot appears in search results — make it count
SPECS:VIDEO_DELIVERY¶
WEB_VIDEO¶
| Context | Resolution | Codec | Bitrate | FPS | Max Duration |
|---|---|---|---|---|---|
| Hero background | 1920x1080 | H.264 | 5-8 Mbps | 30 | 15s (loop) |
| Section embed | 1280x720 | H.264 | 2-4 Mbps | 30 | no limit |
| Tutorial | 1920x1080 | H.264 | 5-8 Mbps | 30 | 5 min |
| Thumbnail preview | 480x270 | H.264 | 500 Kbps | 15 | 5s |
<video
src="/video/product-demo.mp4"
poster="/img/product-demo-poster.webp"
preload="none"
width="1920"
height="1080"
playsinline
muted
>
<track kind="captions" src="/video/captions-en.vtt" srclang="en" label="English" default>
<p>Your browser does not support video. <a href="/video/product-demo.mp4">Download the video</a>.</p>
</video>
RULE: always include poster — prevents blank frame before load
RULE: preload="none" for below-the-fold — saves bandwidth
RULE: playsinline for iOS — prevents fullscreen on play
RULE: background videos must be muted — browsers block unmuted autoplay
RULE: always include <track> for captions (see accessibility-media.md)
SOCIAL_VIDEO¶
INSTAGRAM:
| Type | Dimensions | Max Length | Max Size | FPS |
|------|-----------|-----------|----------|-----|
| Feed | 1080x1080 (1:1) | 60 min | 4 GB | 30 |
| Story | 1080x1920 (9:16) | 60s | 4 GB | 30 |
| Reel | 1080x1920 (9:16) | 90s | 4 GB | 30 |
LINKEDIN:
| Type | Dimensions | Max Length | Max Size | FPS |
|------|-----------|-----------|----------|-----|
| Feed | 1920x1080 (16:9) | 10 min | 5 GB | 30 |
| Vertical | 1080x1920 (9:16) | 10 min | 5 GB | 30 |
FACEBOOK:
| Type | Dimensions | Max Length | Max Size | FPS |
|------|-----------|-----------|----------|-----|
| Feed | 1280x720 min | 240 min | 10 GB | 30 |
| Story | 1080x1920 | 120s | 4 GB | 30 |
X (TWITTER):
| Type | Dimensions | Max Length | Max Size | FPS |
|------|-----------|-----------|----------|-----|
| Feed | 1280x720 min | 140s | 512 MB | 40 |
FORMAT: H.264 MP4 for all platforms
RULE: first 3 seconds are critical — hook viewer immediately
RULE: always burn in captions for social (most view without sound)
RULE: test on mobile before posting — most social consumption is mobile
MOBILE_VIDEO¶
| Target | Resolution | Bitrate | CRF |
|---|---|---|---|
| WiFi | 1080p | 4-6 Mbps | 20 |
| 4G | 720p | 1.5-3 Mbps | 23 |
| 3G | 480p | 500K-1M | 26 |
RULE: provide multiple quality levels or use adaptive streaming (HLS/DASH)
RULE: BunnyCDN Stream handles adaptive quality automatically
SPECS:EMAIL_IMAGES¶
CONSTRAINTS¶
- MAX file size per image: 200 KB (many email clients have total size limits)
- MAX email total size: 500 KB for optimal delivery
- FORMAT: JPEG or PNG only (no WebP, no AVIF — email clients don't support them)
- WIDTH: max 600px (standard email container width)
- RETINA: provide 1200px wide for retina displays, set
width="600"in HTML - ALT_TEXT: mandatory — many users block images by default
- INLINE_CSS: all styles must be inline
<img
src="https://cdn.example.com/email/hero.jpg"
alt="Your monthly report is ready — click to view dashboard"
width="600"
height="300"
style="display: block; max-width: 100%; height: auto;"
>
RULE: always use absolute URLs for email images — relative paths break
RULE: host on CDN with long cache TTL — email images are fetched on open, not on send
RULE: GIFs supported for simple animation (keep under 1MB, 3-5 frames)
RULE: test in Outlook, Gmail, Apple Mail at minimum
SPECS:PRESENTATION_ASSETS¶
SLIDE_IMAGES¶
RESOLUTION: 1920x1080 (16:9 standard)
FORMAT: PNG (for quality) or JPEG (for photos)
MAX_SIZE: 2 MB per image
RULE: no transparency needed — slides have solid backgrounds
VIDEO_IN_SLIDES¶
FORMAT: H.264 MP4
RESOLUTION: 1920x1080
BITRATE: 8-12 Mbps (higher than web — local playback)
RULE: embed video, don't stream — presentations may be offline
RULE: keep videos under 30 seconds — presentations shouldn't be movie screenings
SPECS:FAVICON_AND_PWA¶
FAVICON_SET¶
| File | Size | Format |
|---|---|---|
| favicon.ico | 16x16, 32x32 (multi-res) | ICO |
| apple-touch-icon.png | 180x180 | PNG |
| favicon-32x32.png | 32x32 | PNG |
| favicon-16x16.png | 16x16 | PNG |
| android-chrome-192x192.png | 192x192 | PNG |
| android-chrome-512x512.png | 512x512 | PNG |
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
PWA_MANIFEST¶
{
"name": "Growing Europe",
"short_name": "GE",
"icons": [
{ "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" },
{ "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
],
"theme_color": "#2563EB",
"background_color": "#FFFFFF",
"display": "standalone"
}
RULE: maskable icon needs safe zone (center 80%) — important content must be within circle
CROSS_REFERENCES¶
- Asset optimization (format conversion, compression): asset-optimization.md
- Image generation: image-generation.md
- Video production pipeline: video-production.md
- Accessibility requirements: accessibility-media.md