How to Identify and Extract Layered Images (Background and Overlay) in the AI Website Cloner Template

To identify and extract layered images like background and overlay compositions, enumerate all <img> elements and CSS background-image values within each container, record their stacking contexts, and download each asset separately to preserve the visual hierarchy.

The JCodesMore/ai-website-cloner-template treats every visual asset as a first-class building block, requiring precise extraction of layered graphics to ensure regenerated sites maintain pixel-perfect fidelity. When a target page uses composite visuals—such as a watercolor background paired with a foreground UI mockup or icons positioned over gradients—each layer must be captured as a separate image file. Missing any layer results in incomplete visual reproduction, even when the corresponding CSS is perfectly cloned.

Understanding Layered Image Assets in Website Cloning

Layered graphics are fundamental to modern marketing pages, hero sections, and complex card components. The template's workflow explicitly recognizes that a section appearing as one image often contains multiple layers that require individual extraction.

According to the source code in .windsurf/workflows/clone-website.md, agents must enumerate ALL <img> elements and background images within a section, including absolutely-positioned overlays. Similarly, .github/skills/clone-website/SKILL.md mandates identification of layered images comprising multiple <img> tags or background-images stacked within the same container. The docs/research/INSPECTION_GUIDE.md further emphasizes capturing Z-index layers—such as navigation, modals, tooltips, and overlays—which frequently correspond to separate image assets.

Step-by-Step Layered Image Extraction Workflow

Inspect the DOM Structure

Open the target website in Chrome DevTools and traverse the DOM of each component or section you plan to clone. Group assets by container, treating each "section" as a single logical UI block. If a container contains more than one image source (e.g., an <img> tag plus a CSS background-image), treat each as a distinct layer requiring separate extraction.

Capture All Image Sources

For every element within the target container, collect:

  • <img> tags: Record src, alt attributes, and natural dimensions.
  • CSS background images: Extract url(...) values from computed styles, including any data URIs.

Store these references with their associated metadata to ensure accurate reconstruction in the Next.js application.

Record Stacking Context and Z-Index

Document each layer's stacking context by capturing z-index, position, and opacity values from computed styles. This metadata ensures that when you regenerate the component using next/image or custom wrappers, the visual hierarchy matches the original composition exactly.

Practical Implementation: Browser and Node Scripts

Browser Console Script for Layer Detection

Run the following JavaScript in your browser's DevTools console to harvest layered assets from the target page:

// Collect all image sources for a given container element
function collectLayeredImages(container) {
  const layers = [];

  // <img> elements
  container.querySelectorAll('img').forEach(img => {
    layers.push({
      type: 'img',
      src: img.src,
      alt: img.alt,
      width: img.naturalWidth,
      height: img.naturalHeight,
      zIndex: getComputedStyle(img).zIndex || 0,
    });
  });

  // CSS background images (including gradients that resolve to a URL)
  const style = getComputedStyle(container);
  const bgImg = style.backgroundImage;
  if (bgImg && bgImg !== 'none') {
    const urlMatch = bgImg.match(/url\(["']?(.*?)["']?\)/);
    if (urlMatch) {
      layers.push({
        type: 'background',
        src: urlMatch[1],
        zIndex: style.zIndex || 0,
      });
    }
  }

  return layers;
}

// Example: run on every section with a data-section attribute
const allSections = document.querySelectorAll('[data-section]');
const report = {};

allSections.forEach(sec => {
  const name = sec.getAttribute('data-section') || 'unnamed';
  report[name] = collectLayeredImages(sec);
});

console.log('Layered image report:', report);

This function walks each UI section, pulls every <img> and its CSS background-image, and records the stacking order—directly implementing the "enumerate ALL <img> elements" requirement specified in the Windsurf workflow.

Node.js Download Automation

After collecting URLs from the browser console, use this Node script (compatible with the scripts/download-assets.mjs placeholder) to download assets to your local project:

import fs from 'fs';
import path from 'path';
import https from 'https';
import http from 'http';

const urls = [
  // <-- paste the URLs collected from the console output above
  // 'https://example.com/images/hero-bg.webp',
  // 'https://example.com/images/hero-fg.png',
];

const destDir = path.resolve('public/images');

if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });

function download(url) {
  const client = url.startsWith('https') ? https : http;
  return new Promise((resolve, reject) => {
    const fileName = path.basename(new URL(url).pathname);
    const filePath = path.join(destDir, fileName);
    client.get(url, res => {
      if (res.statusCode !== 200) return reject(new Error(`Failed ${url}`));
      const file = fs.createWriteStream(filePath);
      res.pipe(file);
      file.on('finish', () => file.close(() => resolve(filePath)));
    }).on('error', reject);
  });
}

(async () => {
  for (const u of urls) {
    try {
      const saved = await download(u);
      console.log(`✅ downloaded ${u} → ${saved}`);
    } catch (e) {
      console.error(`❌ error downloading ${u}`, e);
    }
  }
})();

Save the downloaded files to public/images/ using a naming convention that reflects layer order (e.g., hero-bg.webp, hero-fg.png), then reference them in your React components:

import Image from 'next/image';
import heroBg from '@/public/images/hero-bg.webp';
import heroFg from '@/public/images/hero-fg.png';

export function Hero() {
  return (
    <div className="relative h-[600px]">
      <Image src={heroBg} alt="hero background" fill />
      <Image src={heroFg} alt="hero overlay" fill className="absolute inset-0" />
    </div>
  );
}

Key Source Files and Configuration

The following files in JCodesMore/ai-website-cloner-template define the layered image extraction protocol:

  • .windsurf/workflows/clone-website.md: Contains the primary workflow instruction to enumerate all <img> elements and background images, including absolutely-positioned overlays.
  • .github/skills/clone-website/SKILL.md: Mirrors the workflow requirements for AI agents, specifically calling out layered images with multiple <img> tags or background-images in the same container.
  • docs/research/INSPECTION_GUIDE.md: Provides the comprehensive inspection checklist for Z-index layers, navigation overlays, and modal assets.
  • src/app/layout.tsx: Loads the public/images directory into the Next.js application, making extracted assets available to components.

Summary

  • Layered images require individual extraction of each <img> tag and CSS background-image within a container to preserve visual fidelity.
  • Browser DevTools provide the necessary getComputedStyle API to capture both image URLs and stacking context data (z-index, position).
  • Naming conventions like section-bg.webp and section-fg.png maintain clarity when multiple layers belong to the same UI component.
  • Next.js Image components reconstruct the original composition using absolute positioning based on the captured metadata.

Frequently Asked Questions

How do I distinguish between decorative backgrounds and content images when extracting layers?

Inspect the alt attribute and ARIA roles of <img> elements—functional content images typically have descriptive alt text, while decorative backgrounds implemented via CSS usually lack alternative text. Additionally, check the role attribute: images marked as role="img" with meaningful labels are content, whereas purely presentational assets often use role="presentation" or appear only as background-image values.

What if the target site uses CSS sprites or data URIs for layered graphics?

For CSS sprites, calculate the background-position and background-size values from the computed styles to determine the specific sprite coordinates, then use canvas or image processing tools to slice the individual assets. Data URIs embedded in CSS can be decoded directly—the Node script handles these by writing the base64 content to binary files, preserving transparency and formatting.

Should I extract SVG overlays differently from raster images like PNG or WebP?

Yes. SVG assets should be saved as individual .svg files in public/images/ rather than rasterized, allowing the Next.js application to scale them losslessly. When the browser console script detects an SVG source (either as an <img> src or CSS background), flag it for vector preservation to maintain crisp edges at all resolutions.

How do I handle dynamically loaded images that appear only after scrolling or interaction?

Use Chrome DevTools' Network panel to monitor image requests triggered by scroll events or JavaScript interactions. Alternatively, programmatically trigger these events in the console using element.scrollIntoView() or element.click() before running the extraction script, ensuring lazy-loaded layers are present in the DOM when you collect the asset URLs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →