UTA DevHub

Performance Optimization

Comprehensive performance optimization strategies for brand assets including image compression, font loading, animation memory management, and build-time optimization techniques

Brand Assets Performance Optimization

Overview

Brand asset performance directly impacts app startup time, memory usage, and user experience. This guide covers optimization strategies specifically for images, fonts, animations, and other brand assets—distinct from UI icon optimization.

Scope: This guide focuses on brand assets (logos, illustrations, fonts, animations). For UI icon performance optimization, see Performance Optimization.

Image Performance Optimization

Bundle Size Analysis for Images

Metro Bundle Analyzer Setup

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
 
const config = getDefaultConfig(__dirname);
 
// Enable bundle analysis for images
if (process.env.ANALYZE_BUNDLE === 'true') {
  config.transformer = {
    ...config.transformer,
    assetExts: [...config.transformer.assetExts, 'png', 'jpg', 'jpeg', 'svg'],
  };
}
 
module.exports = config;

Image Compression Strategies

Lossless Optimization

Start with lossless optimization to reduce file size without quality loss

# PNG optimization
pngquant --quality=80-95 assets/brand/**/*.png
 
# JPEG optimization  
jpegoptim --max=85 assets/brand/**/*.jpg

Format Selection

Choose the most efficient format for each image type

const getOptimalFormat = (imageType: string, hasTransparency: boolean) => {
  if (hasTransparency) return 'PNG';
  if (imageType === 'photo') return 'JPEG';
  if (imageType === 'logo') return 'SVG';
  return 'WebP'; // Best compression for supported devices
};

Multi-Resolution Optimization

Optimize each resolution variant appropriately

# Different quality for different resolutions
imagemin assets/brand/logos/logo.png --quality=80-90    # 1x
imagemin assets/brand/logos/logo@2x.png --quality=85-95 # 2x
imagemin assets/brand/logos/logo@3x.png --quality=90-98 # 3x

Font Performance Optimization

Font Loading Optimization

// core/performance/FontLoader.ts
import * as Font from 'expo-font';
import AsyncStorage from '@react-native-async-storage/async-storage';
 
export class OptimizedFontLoader {
  private static fonts = {
    'Inter-Regular': require('@/assets/fonts/Inter-Regular.ttf'),
    'Inter-Medium': require('@/assets/fonts/Inter-Medium.ttf'),
    'Inter-Bold': require('@/assets/fonts/Inter-Bold.ttf'),
  };
  
  static async loadEssentialFonts(): Promise<boolean> {
    try {
      // Check cache first
      const cached = await AsyncStorage.getItem('fonts_loaded_v2');
      if (cached) return true;
      
      // Load with timeout
      await Promise.race([
        Font.loadAsync(this.fonts),
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error('Font load timeout')), 5000)
        )
      ]);
      
      await AsyncStorage.setItem('fonts_loaded_v2', 'true');
      return true;
      
    } catch (error) {
      console.warn('Font loading failed, using system fonts:', error);
      return false;
    }
  }
}

Font Bundle Optimization

// scripts/optimize-fonts.js
class FontBundleOptimizer {
  analyze() {
    const fonts = this.scanFonts();
    return {
      fonts,
      totalSize: fonts.reduce((sum, font) => sum + font.size, 0),
      recommendations: this.generateRecommendations(fonts),
    };
  }
  
  generateRecommendations(fonts) {
    const recommendations = [];
    const oversized = fonts.filter(f => f.size > 200 * 1024);
    
    if (oversized.length > 0) {
      recommendations.push(`${oversized.length} fonts exceed 200KB - consider subsetting`);
    }
    
    return recommendations;
  }
}

Animation Performance

Lottie Animation Optimization

// components/OptimizedLottieView.tsx
import React, { useEffect, useRef, useState } from 'react';
import LottieView from 'lottie-react-native';
import { AppState } from 'react-native';
 
export const OptimizedLottieView: React.FC<any> = ({
  source,
  autoPlay = false,
  loop = false,
  ...props
}) => {
  const animationRef = useRef<LottieView>(null);
  const [isAppActive, setIsAppActive] = useState(true);
  
  useEffect(() => {
    const subscription = AppState.addEventListener('change', (nextAppState) => {
      const isActive = nextAppState === 'active';
      setIsAppActive(isActive);
      
      if (animationRef.current) {
        if (isActive && autoPlay) {
          animationRef.current.play();
        } else {
          animationRef.current.pause();
        }
      }
    });
    
    return () => subscription?.remove();
  }, [autoPlay]);
  
  return (
    <LottieView
      ref={animationRef}
      source={source}
      autoPlay={autoPlay && isAppActive}
      loop={loop}
      renderMode="SOFTWARE" // Better performance for complex animations
      {...props}
    />
  );
};

Performance Monitoring

Asset Performance Metrics

// utils/AssetPerformanceMonitor.ts
export class AssetPerformanceMonitor {
  private static metrics = {
    imageLoads: [] as Array<{name: string; time: number; size: number}>,
    fontLoads: [] as Array<{family: string; time: number; success: boolean}>,
  };
  
  static recordImageLoad(name: string, loadTime: number, sizeBytes: number): void {
    this.metrics.imageLoads.push({ name, time: loadTime, size: sizeBytes });
    
    if (loadTime > 100) {
      console.warn(`Slow image load: ${name} took ${loadTime}ms`);
    }
  }
  
  static getPerformanceReport() {
    const { imageLoads, fontLoads } = this.metrics;
    
    return {
      images: {
        total: imageLoads.length,
        averageLoadTime: imageLoads.reduce((a, b) => a + b.time, 0) / imageLoads.length,
        totalSize: imageLoads.reduce((a, b) => a + b.size, 0),
      },
      fonts: {
        total: fontLoads.length,
        successRate: (fontLoads.filter(f => f.success).length / fontLoads.length) * 100,
      },
    };
  }
}

Production Best Practices

Image Optimization

(Do ✅):

  • Compress images before adding to project
  • Use appropriate formats (SVG for logos, JPEG for photos, PNG for transparency)
  • Provide multi-resolution variants (@1x, @2x, @3x)
  • Preload critical brand images during app initialization

(Don't ❌):

  • Use uncompressed images directly from design tools
  • Include oversized images (>500KB without good reason)
  • Mix up image formats inappropriately

Font Performance

(Do ✅):

  • Load essential font weights first, additional weights on demand
  • Implement font loading timeouts and fallbacks
  • Cache font loading status to avoid re-loading

(Don't ❌):

  • Load all font weights simultaneously at startup
  • Use fonts without fallback strategies
  • Block app startup for font loading

Animation Performance

(Do ✅):

  • Optimize Lottie JSON files before use
  • Pause animations when app is backgrounded
  • Limit concurrent complex animations

(Don't ❌):

  • Run multiple complex animations simultaneously
  • Keep animations playing when not visible
  • Skip animation performance testing on low-end devices

Remember: Brand asset performance optimization is an ongoing process. Regular monitoring ensures optimal user experience.