App Store Screenshot Generator: Technical Implementation from html2canvas to High-Quality Export#

Published: May 7, 2026 at 01:35

Why Do You Need an App Store Screenshot Generator?#

When developers submit apps to the App Store or Google Play, they must provide device screenshots as promotional materials. App Store requires iPhone screenshots at 1320×2868 (9:20 aspect ratio), while Google Play demands 1080×1920 (9:16). Manually creating these screenshots is time-consuming—you need to design backgrounds, adjust device frames, position text, and export multiple sizes.

The App Store Screenshot Generator solves this pain point. Developers upload their app screenshots, preview effects in real-time, adjust gradient backgrounds, device frames, and title styles, then export images that meet store specifications with one click.

Core Technical Implementation#

1. Canvas Scaling and Adaptive Device Frames#

The key challenge is that the device frame must scale proportionally to the canvas and cannot exceed canvas boundaries. When users adjust the device width percentage or vertical offset, the maximum height of the device frame must be calculated in real-time.

function calcDeviceSize(
  canvasWidth: number,
  canvasHeight: number,
  widthPercent: number,
  deviceY: number = 0
) {
  const deviceWidth = Math.round(canvasWidth * (widthPercent / 100));
  // Phone aspect ratio 9:16
  const idealHeight = Math.round(deviceWidth * 16 / 9);

  // Calculate maximum available height for device frame
  const halfCanvas = canvasHeight / 2;
  const topSpace = halfCanvas + deviceY;
  const bottomSpace = halfCanvas - deviceY;
  const maxHeight = Math.min(topSpace, bottomSpace) * 2 - 40;

  const deviceHeight = Math.min(idealHeight, maxHeight, Math.round(canvasHeight * 0.7));
  return { deviceWidth, deviceHeight };
}

The core logic: the device frame center is positioned at canvas center + deviceY, with 20px margins on top and bottom, taking the smaller value of top/bottom spaces as available height.

2. html2canvas Export Pitfalls and Solutions#

The App Store Screenshot Generator uses the html2canvas library to convert DOM elements to images. However, several pitfalls were encountered in practice:

Pitfall 1: Blur from Scaling

During preview, the canvas is scaled down to around 22% for display, but export requires original dimensions. If you screenshot the scaled DOM directly, the image will be blurry. The solution is to create a hidden original-size DOM element:

const createExportElement = (s: Screenshot) => {
  const el = document.createElement('div');
  el.style.width = `${s.width}px`;      // Original size, e.g. 1320px
  el.style.height = `${s.height}px`;    // Original size, e.g. 2868px
  el.style.position = 'fixed';
  el.style.left = '-9999px';             // Hidden outside viewport

  // Build DOM structure...
  document.body.appendChild(el);
  return el;
};

Pitfall 2: Cross-Origin Images Cannot Be Exported

If user-uploaded screenshots or background images are cross-origin URLs, html2canvas will throw an error. The solution is to convert images to base64 first:

const onBgUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
  const file = e.target.files?.[0];
  if (!file) return;
  const reader = new FileReader();
  reader.onload = (ev) => {
    update({
      backgroundType: 'image',
      backgroundValue: ev.target?.result as string  // base64 DataURL
    });
  };
  reader.readAsDataURL(file);
};

Pitfall 3: Font Rendering Issues

Some fonts may not render correctly in html2canvas. The solution is to ensure fonts are loaded before export:

// Use Web Font Loader or document.fonts.ready
await document.fonts.ready;

// Then execute html2canvas
const canvas = await html2canvas(element, {
  useCORS: true,
  scale: 1,           // No extra scaling, maintain original size
  backgroundColor: null
});

3. Device Frames and Rounded Corners#

The device frame needs to simulate the appearance of a real phone—borders, rounded corners, and shadows. These effects are implemented through CSS:

const deviceStyle = {
  width: deviceWidth,
  height: deviceHeight,
  border: `${deviceBorder}px solid ${deviceBorderColor}`,
  borderRadius: `${deviceRadius}px`,
  boxShadow: '0 20px 60px rgba(0, 0, 0, 0.4)',
  overflow: 'hidden',
  background: '#000',
  transform: `translate(-50%, -50%) rotate(${deviceRotation}deg)`,
  transformOrigin: 'center center'
};

Key points:

  • overflow: hidden ensures screenshot content doesn’t overflow rounded corners
  • transformOrigin: 'center center' ensures rotation pivots around the center
  • deviceBorder and deviceRadius let users customize device appearance

4. Gradient Backgrounds and Text Shadows#

The tool provides three background types: solid color, gradient, and image. Gradient backgrounds use CSS linear-gradient, combined with text shadows for clearer titles:

// Gradient background
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';

// Text shadow enhances readability
textShadow: '0 2px 20px rgba(0, 0, 0, 0.4)';

5. Batch Export and Download#

Users can add multiple screenshots, and the tool supports batch export. Using the JSZip library to package as a ZIP file:

const exportAll = async () => {
  const zip = new JSZip();

  for (const screenshot of screenshots) {
    const element = createExportElement(screenshot);
    const canvas = await html2canvas(element, { useCORS: true, scale: 1 });
    const blob = await new Promise<Blob>(resolve =>
      canvas.toBlob(b => resolve(b!), 'image/png')
    );
    zip.file(`${screenshot.name}.png`, blob);
    document.body.removeChild(element);  // Clean up temporary DOM
  }

  const zipBlob = await zip.generateAsync({ type: 'blob' });
  saveAs(zipBlob, 'app-store-screenshots.zip');
};

Performance Optimization#

1. Preview Scaling#

Directly rendering a 2868px high DOM would be very laggy. The tool uses scaled preview:

const [scale, setScale] = useState(0.22);  // Scale down to 22%

<div style={{ transform: `scale(${scale})`, transformOrigin: 'top left' }}>
  {/* Original size preview canvas */}
</div>

2. Lazy Loading Background Images#

Background images use lazy loading, only loading when needed:

{backgroundType === 'image' && (
  <img src={backgroundValue} onLoad={() => setLoaded(true)} />
)}

3. Debounced Updates#

When users adjust sliders, use debounce to avoid frequent re-renders:

const update = useCallback(debounce((u: Partial<Screenshot>) => {
  setScreenshots(prev => prev.map(s => s.id === activeId ? { ...s, ...u } : s));
}, 50), [activeId]);

Real-World Use Cases#

  1. iOS App Store Submission - Generate 1320×2868 iPhone screenshots
  2. Google Play Submission - Generate 1080×1920 Android screenshots
  3. Marketing Material Creation - Quickly create multi-language, multi-size promotional images
  4. Product Demos - Display app screenshots in device frames with titles and descriptions

Common Issues#

Q: Why are exported images blurry?

A: Ensure canvas dimensions are set correctly (iPhone 1320×2868, Android 1080×1920), don’t export after scaling down. The tool creates original-size hidden DOM for screenshots.

Q: Fonts don’t display correctly?

A: Ensure fonts are fully loaded. The tool waits for document.fonts.ready before executing export.

Q: Background images won’t display?

A: Cross-origin images need to be converted to base64. The tool uses FileReader to convert uploaded images to DataURL.


The App Store Screenshot Generator implements browser-based screenshot export through html2canvas, solving technical challenges like cross-origin images, scaling blur, and font rendering. Developers can quickly create store-compliant screenshot materials without installing any software.