export type FetchResult = {
html: string;
css: string;
baseUrl: string;
title: string;
metaDescription: string;
};
export type ScreenshotResult = {
base64: string;
viewport: {
width: number;
height: number;
};
};
export type DownloadedImage = {
localPath: string;
fileName: string;
width: number;
height: number;
};
export type ColorUsage = "background" | "text" | "accent" | "border";
export type ExtractedColor = {
value: string;
usage: ColorUsage;
frequency: number;
/** CSS property where the color was found (e.g. "background-color", "color") */
property: string;
};
export type ExtractedFont = {
family: string;
usage: "heading" | "body" | "mono";
};
export type DesignTokens = {
colors: ExtractedColor[];
fonts: ExtractedFont[];
radii: string[];
};
/** Maps to the site's CSS custom properties (--bg-0, --brand, etc.) */
export type ThemeVariables = Record;
export type FieldKind = "text" | "richtext"
/** A resource address — an iframe src, a video file. Never an internal page. */
| "url"
/** A navigation target: an internal page, or an external URL / mailto / tel. */
| "link" | "image" | "imageAlt" | "color" | "enum" | "number";
export type FieldSpec = {
name: string;
kind: FieldKind;
label: string;
required: boolean;
imageSpec?: {
aspectRatio: "landscape" | "square" | "portrait";
width: number;
height: number;
};
enumOptions?: string[];
};
export type ListFieldSpec = {
name: string;
label: string;
itemFields: FieldSpec[];
};
export type BlockCodegenInput = {
/** PascalCase block name, e.g. "PricingTable" */
name: string;
description: string;
category: "content" | "media" | "layout" | "conversion";
fields: FieldSpec[];
listFields?: ListFieldSpec[];
defaultProps: Record;
/** CSS template using design system variables */
cssTemplate: string;
/** JSX body — inner content of the wrapper */
rendererJsx: string;
/** Target directory for generated files, e.g. "apps/site/blocks" */
outputDir: string;
};
export type BlockCodegenResult = {
blockType: string;
filesCreated: string[];
manifestUpdated: string;
};
export type ExtractedSection = {
/** Position on page (0-based) */
index: number;
/** Original HTML tag (section, div, article, etc.) */
tag: string;
/** Element id attribute if present */
id?: string;
/** Semantic CSS class hints extracted from class list */
classHints: string[];
/** Heuristic block type suggestion based on class/content analysis */
suggestedBlockType?: string;
/** Structured content extracted from the section */
content: {
headings: Array<{
level: number;
text: string;
}>;
paragraphs: string[];
images: Array<{
src: string;
alt: string;
isLazy: boolean;
}>;
links: Array<{
href: string;
text: string;
}>;
lists: string[][];
};
/** Trimmed inner HTML (max ~5KB) */
rawHtml: string;
};
/** Compact page outline — captures full page structure in ~3KB regardless of HTML size */
export type PageOutline = {
/** All headings in document order */
headings: Array<{
level: number;
text: string;
}>;
/** Visual sections split at h1/h2 boundaries — each may contain sub-items from h3s */
sections: Array<{
/** Inferred section type */
type: "hero" | "features" | "cards" | "pricing" | "cta" | "text" | "gallery" | "faq" | "stats" | "contact" | "video" | "info-hub" | "unknown";
/** Section heading (from h1/h2) */
heading?: string;
/** First ~120 chars of text content */
contentSummary: string;
/** Sub-items from h3 headings within this section */
subItems?: string[];
imageCount: number;
linkCount: number;
listItemCount: number;
hasForm: boolean;
hasPricing: boolean;
hasVideo: boolean;
/** Elementor widget types found in this section */
widgetTypes?: string[];
/** Repeated element patterns detected visually */
repeatGroups?: RepeatGroup[];
/** How this section was detected */
detectedBy?: "heading" | "visual-gap" | "both";
}>;
totalImages: number;
totalLinks: number;
};
export type LayoutNode = {
tag: string;
depth: number;
rect: {
x: number;
y: number;
w: number;
h: number;
};
text: string;
childCount: number;
imgCount: number;
linkCount: number;
classes: string;
role: string;
widgetType: string;
};
export type VisualSection = {
y: number;
height: number;
nodes: LayoutNode[];
textLength: number;
imgCount: number;
linkCount: number;
};
export type RepeatGroup = {
signature: string;
count: number;
inferredType: "card" | "feature" | "pricing" | "stat" | "testimonial" | "unknown";
itemTexts: string[];
};
/** Extracted navigation structure from the source site */
export type NavExtraction = {
siteName?: string;
logoUrl?: string;
items: Array<{
label: string;
href?: string;
children?: Array<{
label: string;
href: string;
}>;
}>;
};
/** Embedded iframe (YouTube, Vimeo, Google Maps, etc.) */
export type ExtractedEmbed = {
src: string;
type: "youtube" | "vimeo" | "map" | "other";
/** Y position on the page (for correlating with visual sections) */
y: number;
width: number;
height: number;
};
/** Layered image composition — multiple positioned images forming one visual */
export type ImageComposition = {
layers: Array<{
src: string;
alt: string;
zIndex: number;
position: string;
bounds: {
x: number;
y: number;
w: number;
h: number;
};
}>;
compositeType: "stacked" | "overlay" | "single";
};
/** Extracted