How to Detect and Extract Layered Image Compositions in ai-website-cloner-template
Run the browser-side discovery script from .windsurf/workflows/clone-website.md to capture every <img> element's parent context, sibling count, and CSS positioning data, then flag containers with siblingCount > 1 or background-image declarations as layered compositions requiring multi-asset extraction.
The ai-website-cloner-template treats layered images as first-class extraction targets to ensure cloned websites remain pixel-perfect. Unlike single raster files, these compositions consist of multiple stacked assets—background gradients, foreground illustrations, and overlay icons—that must be detected and reconstructed individually. This guide walks through the repository's built-in detection logic and provides the exact JavaScript implementation used to identify these complex visual stacks.
What Are Layered Image Compositions?
Layered image compositions are UI sections that appear as single pictures but are actually constructed from multiple raster or SVG assets stacked via CSS positioning. A typical example combines a background watercolor texture, a foreground UI mock-up, and small icon overlays. According to the docs/research/INSPECTION_GUIDE.md, missing any layer during extraction results in visually incomplete clones, making detection critical for fidelity.
Where Detection Logic Lives
The repository centralizes its layered-asset detection guidance across three key locations:
| Component | File Path | Purpose |
|---|---|---|
| Workflow guidance | .windsurf/workflows/clone-website.md |
Narrative explaining that sections may contain multiple layers; requires enumerating all <img> and background-image elements. Contains the extraction script at lines 88-124. |
| CLI reference | .opencode/commands/clone-website.md |
Duplicates the layered-asset requirements for command-line agent usage. |
| Inspection checklist | docs/research/INSPECTION_GUIDE.md |
High-level audit checklist explicitly flagging "Z-index layers" and "Layered assets matter" as critical inspection points. |
Step-by-Step Detection Process
Running the Browser Discovery Script
Detection executes within the target page's browser context using Chrome MCP, Playwright MCP, or any supported browser tool. The script gathers comprehensive metadata for every image element to reveal stacking relationships.
The process iterates over all <img> elements and extracts:
src,alt, and natural dimensionsparentClasses– CSS classes of the direct container (img.parentElement?.className)siblingCount– Number of sibling<img>elements in the same parent ([...img.parentElement.querySelectorAll('img')].length)positionandzIndex– Computed CSS values to identify absolutely-positioned overlays
Additionally, the script scans every DOM node for non-none backgroundImage values and records the element's tag and class.
Identifying Stacked Layers
A container qualifies as a layered composition when the returned JSON shows either:
siblingCount > 1inside the same parent element- Presence of both a background-image declaration and child
<img>elements within the same container
These patterns indicate stacked visual assets requiring separate extraction.
Code Implementation
Browser Extraction Script
Execute this script in the browser console (as implemented in .windsurf/workflows/clone-website.md lines 88-124) to generate the layer map:
// Run via browser MCP (Chrome DevTools or Playwright)
const layers = (() => {
// Gather <img> elements with parent context
const imgs = [...document.querySelectorAll('img')].map(img => ({
src: img.src || img.currentSrc,
alt: img.alt,
width: img.naturalWidth,
height: img.naturalHeight,
parentClasses: img.parentElement?.className ?? '',
siblingCount:
img.parentElement
? [...img.parentElement.querySelectorAll('img')].length
: 0,
position: getComputedStyle(img).position,
zIndex: getComputedStyle(img).zIndex,
}));
// Gather background-image declarations
const bgs = [...document.querySelectorAll('*')]
.filter(el => {
const bg = getComputedStyle(el).backgroundImage;
return bg && bg !== 'none';
})
.map(el => ({
url: getComputedStyle(el).backgroundImage,
element: `${el.tagName.toLowerCase()}.${el.className.split(' ')[0] || ''}`,
}));
return JSON.stringify({ imgs, bgs }, null, 2);
})();
console.log(layers);
Interpreting the Output
Save the JSON output to identify layered compositions. This example shows a detected stack:
{
"imgs": [
{
"src": "/images/hero-bg.jpg",
"alt": "",
"width": 1920,
"height": 1080,
"parentClasses": "hero-section",
"siblingCount": 2,
"position": "relative",
"zIndex": "auto"
},
{
"src": "/images/hero-illustration.png",
"alt": "",
"width": 400,
"height": 350,
"parentClasses": "hero-section",
"siblingCount": 2,
"position": "absolute",
"zIndex": "10"
}
],
"bgs": [
{
"url": "url(\"/images/hero-gradient.png\")",
"element": "section.hero-section"
}
]
}
Here, the hero-section container contains two sibling images (siblingCount: 2) plus a background-image, confirming a three-layer composition.
Extracting and Storing Assets
Downloading Identified Layers
Once detected, download each asset using curl, wget, or a Node.js script. Store them under public/images/ with descriptive prefixes indicating their layer order:
# Example downloads for the hero composition
curl -o public/images/hero-gradient.png https://example.com/images/hero-gradient.png
curl -o public/images/hero-bg.jpg https://example.com/images/hero-bg.jpg
curl -o public/images/hero-illustration.png https://example.com/images/hero-illustration.png
Recording in Component Specs
Document the extracted layers in the component specification's "Assets" block (as defined in the workflow template):
## Assets
- Background image: `public/images/hero-gradient.png`
- Base photo: `public/images/hero-bg.jpg`
- Overlay illustration: `public/images/hero-illustration.png`
Reconstructing in React Components
Assemble the layers in your React component using absolute positioning or Tailwind utilities to preserve the original stacking:
// src/components/HeroSection.tsx
export default function HeroSection() {
return (
<section className="relative overflow-hidden">
{/* Background gradient layer */}
<div
className="absolute inset-0 z-0"
style={{ backgroundImage: 'url(/images/hero-gradient.png)' }}
/>
{/* Base photo layer */}
<img
src="/images/hero-bg.jpg"
alt=""
className="relative z-10 w-full h-auto object-cover"
/>
{/* Overlay illustration layer */}
<img
src="/images/hero-illustration.png"
alt=""
className="absolute inset-0 z-20 m-auto w-48 h-48"
/>
</section>
);
}
Full Pipeline Checklist
Follow this workflow derived from .windsurf/workflows/clone-website.md to ensure complete extraction:
- Run the layer detection script in the target page's browser context
- Verify that any container with
siblingCount > 1or a background-image is logged - Download every identified asset into
public/images/ - Add the assets to the component spec under the Assets heading
- Build the React component using stacked
<img>elements or background-image CSS with properz-indexvalues - Run
npm run buildfollowed bynpx tsc --noEmitto verify compilation
Summary
- Layered compositions are UI sections built from multiple stacked images that appear as single visuals.
- The detection logic resides in
.windsurf/workflows/clone-website.md(lines 88-124) and relies on analyzingsiblingCount,parentClasses, andzIndexvalues. - Browser-side execution via MCP tools captures both
<img>elements and CSSbackground-imagedeclarations. - Containers with multiple sibling images or combined img/background assets require multi-file extraction.
- Store extracted assets in
public/images/and reconstruct layers usingabsolute positioning or Tailwindz-indexutilities in React components.
Frequently Asked Questions
How do I distinguish between a single image and a layered composition?
A single image exists in isolation within its parent container, showing siblingCount: 1 and no background-image on the parent. A layered composition shows siblingCount > 1 (multiple <img> elements sharing a parent) or a combination of background-image CSS and child images. The detection script in .windsurf/workflows/clone-website.md automatically flags these patterns based on DOM structure analysis.
Can I automate the download process for detected layers?
Yes. Pipe the JSON output from the browser script into a Node.js utility script (such as scripts/download-assets.mjs) that iterates over the src and url fields. Use fetch() or https.get() to stream each asset into public/images/ while preserving the original filenames or applying descriptive prefixes like hero-bg and hero-overlay.
What should I do if an image uses CSS background-image instead of an <img> tag?
The detection script specifically queries computed styles for backgroundImage properties across all DOM nodes. These appear in the bgs array of the output JSON. When reconstructing the component, apply these as background-image CSS properties on <div> elements or section containers rather than <img> tags, ensuring you match the original z-index and positioning values captured during detection.
Where does the ai-website-cloner-template expect me to store extracted layered assets?
The template convention places all extracted visual assets in the public/images/ directory. Reference these files in your component specs using relative paths starting with public/images/, and import them in React components using absolute paths like /images/hero-bg.jpg. This ensures Next.js or similar frameworks correctly serve the files as static assets.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →