Website Style Images
Generate images matching a website's visual style. Use this skill when the user wants to: create images in the style of a website, match a website's aesthetic, generate branded images from a URL, create banners/social posts/hero images matching a site's design, extract a website's visual identity and produce images in that style, or replicate a website's look and feel in new images. Also trigger when the user mentions 网站风格图片, 匹配网站风格, 品牌风格图片, 网站设计风格生成, 根据网站生成图片, or 仿站风格.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:ruminate0810~nano-website-style-imagescURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aruminate0810~nano-website-style-images/file -o nano-website-style-images.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/f2d346cf9f5a807b1e2f175dc6f13dd729acb454# Website Style Image Generator
根据目标网站的视觉风格(配色、字体、美学、情绪),生成匹配该风格的各类图片。
## Setup
Set all 4 environment variables before use (all required):
```bash
export NANO_BANANA_ACCESS_KEY="your-access-key"
export NANO_BANANA_SECRET_KEY="your-secret-key"
```
Also set the API URL (required):
```bash
export NANO_BANANA_API_URL="https://your-api-server/task/v1/submit"
export NANO_BANANA_STATUS_URL="https://your-api-server/task/v1/status/{task_id}"
```
## Overview
- **API**: NANO-BANANA (Gemini 3 Pro Image Preview) — async submit/poll/download
- **风格提取**: 双通道(CSS/DOM 数据 + 截图视觉分析)
- **输出类型**: 横幅、社交媒体、产品展示、博客头图、广告等 8 种
- **脚本**: 所有脚本自包含在 `scripts/` 目录中
## Prerequisites
```bash
pip3 install -r requirements.txt
```
## 支持的图片类型
| ID | 名称 | 默认尺寸 | 适用场景 |
|----|------|---------|---------|
| `hero_banner` | 网站横幅 | 1920×600 | 网站首屏/头部横幅 |
| `social_square` | 社交方图 | 1080×1080 | Instagram、微信朋友圈 |
| `social_story` | 社交竖图 | 1080×1920 | Instagram/抖音 Story |
| `social_landscape` | 社交横图 | 1200×628 | Facebook/LinkedIn 分享 |
| `product_display` | 产品展示 | 1200×1200 | 产品展示图 |
| `blog_header` | 博客头图 | 1200×630 | 博客文章头图 |
| `ad_banner` | 广告横幅 | 1200×628 | 数字广告 |
| `custom` | 自定义 | 用户指定 | 其他用途 |
---
## Workflow
### Phase 0 — 用户需求
**在任何提取之前,先和用户确认三个问题。**
**问题 1:你想设计什么?**
| 选项 | 说明 |
|------|------|
| 品牌宣传图 | 展示品牌形象、slogan、价值主张 |
| 产品推广图 | 突出产品、功能、卖点 |
| 社交媒体内容 | 日常帖子、活动预告、节日营销 |
| 广告素材 | 信息流广告、展示广告 |
| 内容配图 | 博客、文章、教程配图 |
| UI/界面设计 | App 启动页、功能介绍、引导页 |
| 电商图 | 产品主图、详情页、促销 banner |
| 线下物料 | 传单、展架、包装、周边 |
**问题 2:用在哪个平台?**(根据问题 1 智能展示对应选项)
| 设计类型 | 平台选项 → 自动尺寸 |
|---------|-------------------|
| 社交媒体 | Instagram(1080×1080) / 小红书(1080×1440) / 朋友圈(1080×1080) / Facebook(1200×628) / LinkedIn(1200×628) / TikTok(1080×1920) |
| 广告素材 | Google Ads(1200×628) / Facebook Ads(1080×1080) / 抖音信息流(1080×1920) |
| 电商图 | 淘宝主图(800×800) / Amazon(2000×2000) / Shopify(2048×2048) |
| UI设计 | iOS(1242×2688) / Android(1440×3120) / Web(1920×1080) |
| 线下物料 | A4传单(2480×3508) / 展架(2362×5315) / 名片(1050×600) |
| 内容配图 | 博客头图(1200×630) / 微信公众号(900×383) |
| 品牌/产品 | Hero Banner(1920×600) / 产品展示(1200×1200) |
**问题 3:风格从哪来?**
| 选项 | 说明 | 后续流程 |
|------|------|---------|
| 提供网站 URL (Recommended) | 从网站提取配色、字体、设计语言 | → Phase 1 完整提取 |
| 上传截图/图片 | App 截图、品牌手册、竞品图片、任何参考图 | → Phase 1(仅视觉分析,`css_data = {}`) |
| 多个竞品对比 | 提供 2-3 个 URL,分析后选最佳 | → Phase 1 逐个提取后合并 |
| 直接描述风格 | 不需要参考,直接告诉我想要的风格 | → Phase 1(手动构建 style profile) |
收集完三个答案后,进入 Phase 1。
---
### Phase 1 — 风格提取
根据 Phase 0 问题 3 的选择,执行对应的提取流程。
#### Step 1a: CSS/DOM 数据提取(仅有 URL 时执行)
使用 Chrome MCP `navigate` 打开目标网站,然后用 `javascript_tool` 注入以下脚本。
脚本使用元素面积加权颜色重要性,提取字体粗细、letter-spacing、line-height、渐变色值、阴影参数,并跳过不可见元素:
```javascript
(function() {
const els = document.querySelectorAll('*');
const colorMap = {}, bgColorMap = {};
const fonts = new Set(), headingFonts = new Set();
const fontWeights = { heading: [], body: [] };
const letterSpacings = [], lineHeights = [];
let hasGradient = false, hasShadow = false;
let shadowDetail = '';
const radiusValues = [];
const gradientColors = new Set();
els.forEach(el => {
const s = window.getComputedStyle(el);
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return;
// Area-weighted color collection
const rect = el.getBoundingClientRect();
const area = Math.max(1, rect.width * rect.height);
const weight = Math.min(10, Math.ceil(area / 10000));
const color = s.color;
const bg = s.backgroundColor;
if (color && color !== 'rgba(0, 0, 0, 0)') {
colorMap[color] = (colorMap[color] || 0) + weight;
}
if (bg && bg !== 'rgba(0, 0, 0, 0)') {
bgColorMap[bg] = (bgColorMap[bg] || 0) + weight;
}
// Font extraction with weight
const fontName = s.fontFamily.split(',')[0].trim().replace(/['"]/g, '');
if (fontName) fonts.add(fontName);
const isHeading = ['H1','H2','H3','H4','H5','H6'].includes(el.tagName);
if (isHeading) {
headingFonts.add(fontName);
fontWeights.heading.push(s.fontWeight);
} else {
fontWeights.body.push(s.fontWeight);
}
// Letter-spacing (px)
const ls = parseFloat(s.letterSpacing);
if (!isNaN(ls) && ls !== 0) letterSpacings.push(ls);
// Line-height (ratio)
const lh = parseFloat(s.lineHeight);
const fs = parseFloat(s.fontSize);
if (!isNaN(lh) && !isNaN(fs) && fs > 0) lineHeights.push(lh / fs);
// Border radius
const r = parseFloat(s.borderRadius);
if (r > 0) radiusValues.push(r);
// Gradient extraction with actual colors
if (s.backgroundImage && s.backgroundImage.includes('gradient')) {
hasGradient = true;
const matches = s.backgroundImage.match(/rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}/g);
if (matches) matches.forEach(c => gradientColors.add(c));
}
// Shadow detail extraction (first significant one)
if (s.boxShadow && s.boxShadow !== 'none' && !shadowDetail) {
hasShadow = true;
shadowDetail = s.boxShadow.length > 100 ? s.boxShadow.substring(0, 100) : s.boxShadow;
}
});
const sortByWeight = obj => Object.entries(obj).sort((a,b) => b[1]-a[1]).map(e => e[0]);
const modeFn = arr => {
if (!arr.length) return 'normal';
const freq = {};
arr.forEach(v => freq[v] = (freq[v]||0)+1);
return Object.entries(freq).sort((a,b) => b[1]-a[1])[0][0];
};
return JSON.stringify({
textColors: sortByWeight(colorMap).slice(0, 20),
backgroundColors: sortByWeight(bgColorMap).slice(0, 20),
bodyFonts: [...fonts].slice(0, 10),
headingFonts: [...headingFonts].slice(0, 5),
fontWeights: {
heading: modeFn(fontWeights.heading),
body: modeFn(fontWeights.body)
},
letterSpacings: letterSpacings.slice(0, 10),
lineHeights: lineHeights.slice(0, 10),
avgBorderRadius: radiusValues.length ?
radiusValues.reduce((a,b) => a+b,0) / radiusValues.length : 0,
hasGradient, hasShadow, shadowDetail,
gradientColors: [...gradientColors].slice(0, 10)
});
})()
```
保存返回的 JSON 为 `css_data`。
**如果用户上传截图/图片而非 URL**:`css_data = {}`,跳过本步骤,直接进入 Step 1b。
#### Step 1b: 截图与视觉分析
**有 URL 时**:使用 Chrome MCP `computer` 的 `screenshot` 动作截取页面,保存到 `/tmp/website_style_screenshot.png`。
**用户上传截图/图片时**:直接使用用户提供的图片文件。
使用 Read 工具读取图片,用 Claude Vision 分析以下内容:
| 字段 | 描述 | 示例值 |
|------|------|--------|
| `aesthetic` | 整体美学风格 | minimalist, bold, playful, corporate, luxury, tech, organic |
| `palette_mood` | 色彩情绪 | warm, cool, monochromatic, vibrant, muted, earthy |
| `spacing` | 布局间距 | generous whitespace, tight, balanced, airy |
| `photo_style` | 图像风格 | studio photography, flat illustrations, 3D renders, abstract |
| `icon_style` | 图标风格 | 线性图标, 填充图标, 3D 图标, 无图标 |
| `illustration_style` | 插画风格 | 扁平插画, 等距插画, 手绘, 无插画 |
| `photography_treatment` | 摄影处理 | 高对比度, 去饱和, 暖调滤镜, 自然 |
| `pattern_style` | 图案/纹理 | 几何图案, 有机纹理, 噪点, 无 |
| `density` | 信息密度 | 极简, 适中, 密集 |
| `mood_keywords` | 3-5个情绪关键词 | ["professional", "premium", "trustworthy"] |
| `brand_personality` | 品牌个性 | "sophisticated, authoritative, modern tech" |
| `typography_feel` | 字体整体感觉 | "modern, clean", "classic, elegant" |
| `layout_style` | 布局结构 | "grid-based", "asymmetric", "centered single-column" |
将分析结果整理为 `screenshot_analysis` 字典。
#### Step 1c: 网站素材提取(仅有 URL 时执行)
使用 Chrome MCP `javascript_tool` 提取网站中的图片资源:
```javascript
(function() {
const assets = [];
// Logo / Favicon
const favicon = document.querySelector('link[rel*="icon"]');
if (favicon) assets.push({type: 'logo', url: favicon.href});
const ogImage = document.querySelector('meta[property="og:image"]');
if (ogImage) assets.push({type: 'og_image', url: ogImage.content});
// Hero 图和大图
document.querySelectorAll('img').forEach(img