mcpField
W
web-visual-assets

web-visual-assets

github.com/kevintsai1202创意与媒体5265 次安装24 周前更新
代码仓库

关于 web-visual-assets

web-visual-assets 是为教学网站制作并集成视觉素材的技能,涵盖截图、生成式插图、SVG 图表和二维码,并提供回退与覆盖检查方法。

主要功能

  1. 01使用 Playwright 截取页面
  2. 02生成 AI 插图
  3. 03绘制 SVG 图表
  4. 04生成二维码
  5. 05将素材接入 SPA

适用场景

  1. 01为课程页面添加产品截图
  2. 02统一制作课程概念插图
  3. 03绘制带标签的流程图
  4. 04为课程链接生成二维码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kevintsai1202/teaching-site-skills --skill web-visual-assets

安装后在 Claude Code 中输入/web-visual-assets确认已加载。

详细介绍

网页视觉素材

Schema authority:Illustration 基础结构({name, kind, alt, spec} 和 {kind: 'waived', reason})以及每个单元的 illustrations[] 覆盖下限,定义于 _shared/domain-primitives.md §11。

此技能用于生成教学网站的视觉层。四种素材来源几乎可以满足所有需求,各有不同的取舍。

素材来源决策树

What do you need?
├── Screenshot of a real product/website     → Source 1: Playwright scraping
├── A conceptual scene (workflow, metaphor)  → Source 2: AI image generation
├── A simple diagram (boxes, arrows, labels) → Source 3: Hand-drawn SVG
└── A scannable code / functional artifact   → Source 4: Code generator (QRCode, etc.)

来源 1:Playwright 抓取

适用于工具、网站、个人资料卡的截图。示例工作坊会抓取 6 个 AI 工具的主页和一个 YouTube 讲师频道。

标准无头流程
// scripts/scrape-tools.mjs
import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({ path: `data/tools/${id}.png`, fullPage: false });
await browser.close();
遇到反爬虫拦截时(CDP 模式)

有些网站(Cloudflare、现代 OpenAI 产品)会检测无头 Chromium 并进行拦截。解决方法:通过 CDP 连接到真实的 Chrome:

# scripts/start-cdp-chrome.ps1
Start-Process chrome.exe -ArgumentList '--remote-debugging-port=9222', '--user-data-dir=C:\tmp\cdp-profile'
const browser = await chromium.connectOverCDP('http://localhost:9222');
const page = (await browser.contexts()[0].pages())[0];
// ... drive an existing real-browser session

使用 --cdp --pause 标志运行,以便人工完成任何 CAPTCHA,然后按 Enter 继续。

子集合并模式(不要覆盖其他项)

重新抓取多项中的某一项时,应与现有数据合并,而不是覆盖:

async function writeMerged(jsonPath, updates) {
  const existing = JSON.parse(await fs.readFile(jsonPath, 'utf8').catch(() => '{}'));
  await fs.writeFile(jsonPath, JSON.stringify({ ...existing, ...updates }, null, 2));
}

CLI:node scrape-tools.mjs --ids codex,notebooklm 只会处理这两项。

YouTube 频道相关问题
  • 频道页面是一个 SPA。URL 查询字符串(如 ?sort=p&view=0)会被移除。获取最新的 N 个视频后,在客户端进行排序。
  • 虚拟滚动会从视野外的 <img> 中移除 src。请根据 videoId 推导缩略图 URL:https://img.youtube.com/vi/{videoId}/hqdefault.jpg。不要依赖 DOM src。

来源 2:AI 图像生成

适用于场景插图、每日主视觉、概念场景。示例工作坊使用 Gemini 的图像生成功能;任何文生图 API 都可以。

提示词设计规则
  1. 为整个课程指定一致的视觉风格(例如:“扁平插画、柔和的粉彩色调、无文字、无人像”)。插画风格不一致会显得不专业。
  2. 避免人脸和品牌 Logo——AI 图像生成器难以处理两者,生成的效果也会显得不自然。
  3. 将提示词与图像一起保存:
assets/illustrations/
├── day1-token-prediction.png
├── day1-token-prediction.prompt.md   ← regenerate-ready prompt
└── ...

这样以后可以重新生成更高质量的图像,或调整风格。

PNG + SVG 备用渲染

AI 生成偶尔会失败(速率限制、内容过滤器、模型问题)。为每张 AI PNG 配上一张手绘 SVG 备用图,并使用相同的路径主干:

function renderIllustration(name) {
  const img = el('img', { src: `assets/illustrations/${name}.png`, alt: '' });
  img.onerror = () => { img.src = `assets/illustrations/${name}.svg`; img.onerror = null; };
  return img;
}

浏览器会先尝试 PNG;遇到 404 时则切换到 SVG。即使从未用到,备用图也会一并发布,以防链接失效。

来源 3:手绘 SVG

适用于需要精确控制的图表:带名称方框之间的箭头、逐步流程、带标注的 UI 模拟图、教室地图。

手写 SVG(或从 Figma/Excalidraw 导出)比 AI 更适合以下内容:

  • 文本标签(AI 无法可靠地在图像中渲染中文)
  • 箭头与方框流程(AI 容易弄错布局)
  • 需要随课程详情变化而更新的内容

样式提示:即使 SVG 本身是线稿,也可以将其放入半透明容器,并添加 drop-shadow 滤镜,使其与网站的整体视觉风格一致。

来源 4:生成代码(QR)

import QRCode from 'qrcode';
await QRCode.toFile('assets/qr/workshop-url.png', 'https://your-workshop.example/', {
  width: 512,
  margin: 1,
  color: { dark: '#000000', light: '#FFFFFF' }
});

对于深色主题的网站,应生成白底深色码,而不是深底白色码——大多数 QR 扫描器都要求浅色背景上的深色前景。

素材文件夹规范

assets/
├── tools/             ← Source 1: scraped tool/product screenshots
├── illustrations/     ← Source 2 (PNG) + Source 3 (SVG fallback)
├── scenarios/         ← Source 2: per-unit scene illustrations
├── cases/             ← Source 2: shared case visuals
├── characters/        ← Source 2: persona portraits
├── qr/                ← Source 4: QR codes
└── maps/              ← Source 1 (screenshot) or Source 3 (SVG)

将素材接入 SPA

在 course-data.js 中,每个单元都有一个 illustrations[] 数组(包含 1–3 个条目),其内容来自 Stage 2 编写的 圖片需求 区块:

{
  id: 'u-3',
  title: '...',
  illustrations: [
    { name: 'day1-u3-hero.png',    kind: 'hero',       alt: '...', spec: '...' },
    { name: 'day1-u3-flow.svg',    kind: 'diagram',    alt: '...', spec: '...' },
    { name: 'day1-u3-example.png', kind: 'screenshot', alt: '...', spec: '...' }  // optional 3rd
  ],
  // ...
}

renderUnit 会遍历 unit.illustrations 并调用 renderIllustration(entry),后者会为每个条目处理优先使用 PNG / 备用使用 SVG 的逻辑。按此顺序渲染主视觉(首屏上方)、图表和截图。

旧版单个 illustration 字段:较旧的 course-data.js 文件使用 illustration: 'foo.png'(单个字符串)。请将其视为 illustrations: [{ name: 'foo.png', kind: 'hero' }],并在方便时迁移为数组形式。新网站不要依赖旧版结构。

覆盖下限(硬性规则——每个单元 1–3 张插图)

只配有封面图的教学网站看起来像未完成的草稿——Stage 5 必须达到最低覆盖要求,才能宣布网站功能完备:

  • course-data.js 中的每个单元都满足 illustrations.length >= 1(且 <= 3)。
  • 每个单元至少有一项对应 assets/ 下的实际文件(PNG 或 SVG)。所有内容都只是占位符(各处均为 { kind: 'placeholder' })的单元不合格。
  • 确实不需要图片的单元必须明确豁免:illustrations: [{ kind: 'waived', reason: '...' }]。未作说明——也就是使用空数组——不满足下限要求。
  • 除各单元图片外,还必须有封面图(assets/cover.png 或同等文件)。封面图不计入任何单元的 1–3 张配额。

未达到下限要求时,不得宣布网站“功能完备”,也不得启动 Stages 5b / 6——编排器层面的强制检查见 teaching-site/SKILL.md 中的 Stage 5 Image Coverage Floor。

批量生成模式(推荐)

不要一次只为一个单元生成图片。应根据 course-data.js 构建清单并批量处理:

// scripts/generate-illustrations.mjs
const manifest = [];
for (const dayKey of ['day1', 'day2', 'day3', 'day4']) {
  for (const unit of window.COURSE[dayKey].units) {
    for (const ill of (unit.illustrations || [])) {
      if (ill.kind === 'waived') continue;
      manifest.push({ name: ill.name, prompt: ill.spec, kind: ill.kind });
    }
  }
}
// → feed manifest to AI image API in parallel batches of 4–6

批量处理的原因:保持风格一致。临时逐个生成单元的图片会导致风格漂移。使用相同风格前缀批量生成,才能形成统一的视觉体系。

验证

需要关注两项验证工作,分别使用不同的技能:

  • “引用的资源是否存在于磁盘上?”(跨文件引用检查)→ 调用 web-content-audit。它的 Audit 1(Cross-Artifact Reference Resolution)和资源覆盖审计正好涵盖此项。
  • “资源能否在浏览器中正常呈现且不出现 404?”(运行时检查)→ 调用 web-visual-verification。多视口验证脚本会收集 console.error,自动检测失效的 <img> 请求。

每次部署前都要运行两项检查。审计会捕获对不存在文件的引用;验证则会捕获文件确实存在、但在渲染后的 HTML 中路径错误的资源。两者的失败方式不同,需要使用不同的脚本。

反模式

  • 逐张生成图片,却不保持风格一致——只编写一次风格规范,并将其作为每个提示词的前缀。
  • 在图片中生成 AI 文本——几乎总会出错;凡是需要准确文字的图片,都应使用 SVG。
  • AI 生成的 PNG 没有 SVG 备用方案——PNG 链接失效(文件被删除或重命名错误)时,网站会显示破损图片图标;SVG 备用方案则能优雅降级。
  • 保存截图却没有重新抓取脚本——六个月后有人想获取新截图时,却找不到当初生成原始截图的方法记录。

交接

告知用户:“视觉资源已就位。运行 node scripts/verify-assets.mjs,确认没有遗漏。网站现在功能完备。下一阶段(course-ebook-publishing)可以将相同内容转换为 PDF/DOCX 交付物——只有在网页版稳定后才调用该阶段。”

评论

支持 Markdown