mcpField
W
web-visual-assets

web-visual-assets

github.com/kevintsai1202クリエイティブ・メディア5265 回インストール24 週間前に更新
リポジトリ

web-visual-assets について

web-visual-assetsは、教育サイト向けのビジュアル素材を作成・統合するスキルです。スクリーンショット、生成画像、SVG図、QRコードに対応し、フォールバックと網羅性の確認方法も扱います。

主な機能

  1. 01Playwrightによるスクリーンショット
  2. 02AI生成イラスト
  3. 03手描きSVG図
  4. 04QRコード生成
  5. 05SPAへの素材統合

活用シーン

  1. 01コースページに製品画面を追加する
  2. 02コースの概念図を一貫した画風で作る
  3. 03ラベル付きのフロー図を作成する
  4. 04コースリンクのQRコードを生成する

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/web-visual-assetsを入力して読み込まれたか確認します。

詳細

Web ビジュアルアセット

スキーマの定義元:Illustration プリミティブの形状({name, kind, alt, spec} および {kind: 'waived', reason})と、ユニットごとの illustrations[] カバレッジ下限は、_shared/domain-primitives.md §11 で定義されています。

このスキルでは、教材サイトのビジュアルレイヤーを作成します。4つのアセットソースでほぼすべてのニーズに対応できますが、それぞれトレードオフがあります。

アセットソースの選択フローチャート

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 によるスクレイピング

ツール、Webサイト、プロフィールカードのスクリーンショットに使用します。サンプルのワークショップでは、AIツールのホームページ6件と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キーを押して続行します。

サブセットのマージパターン(他の項目を上書きしない)

複数項目のうち1つだけを再スクレイピングする場合、既存データを上書きするのではなくマージします。

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 は、その2つだけを処理します。

YouTubeチャンネル特有の注意点
  • チャンネルページはSPAです。?sort=p&view=0 のようなURLクエリ文字列は除去されます。最新のN本の動画を取得してから、クライアント側で並べ替えてください。
  • 仮想スクロールでは、表示範囲外の <img> から src が除去されます。videoId からサムネイルURLを導出してください:https://img.youtube.com/vi/{videoId}/hqdefault.jpg。DOMの src に依存しないでください。

ソース2:AI画像生成

シナリオのイラスト、各日のヒーロー画像、概念的なシーンに使用します。サンプルのワークショップではGeminiの画像生成を使用していますが、どのテキスト画像生成APIでも利用できます。

プロンプトの作成ルール
  1. コース全体で一貫したビジュアルスタイルを指定します(例:「フラットなイラスト、柔らかいパステルカラー、テキストなし、人物なし」)。イラストに一貫性がないと、素人っぽく見えます。
  2. 顔やブランドロゴは避けます。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からエクスポートしたSVG)は、次のような用途では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ユニットあたり1~3点の図版)

カバー画像しかない教材サイトは、未完成の草稿のように見えます。サイトを機能完成と宣言する前に、ステージ5で最低カバレッジを満たす必要があります。

  • course-data.js のすべてのユニットで、illustrations.length >= 1(かつ <= 3)であること。
  • 各ユニットに、assets/ 内の実ファイル(PNG または SVG)が少なくとも1点あること。すべてが { kind: 'placeholder' } のユニットは不合格です。
  • 画像を使わない正当な理由があるユニットには、明示的な免除を記載すること:illustrations: [{ kind: 'waived', reason: '...' }]。何も記載しないこと、つまり空の配列は最低基準を満たしません。
  • ユニットごとの画像とは別に、カバー画像(assets/cover.png または同等のもの)があること。カバー画像は、各ユニットの1~3点の上限・下限には含まれません。

最低基準を満たしていない場合、サイトを「機能完成」と宣言できません。また、ステージ5b/6をまだ実行してはいけません。オーケストレーター層での適用については、teaching-site/SKILL.md の「ステージ5 画像カバレッジの最低基準」を参照してください。

バッチ生成パターン(推奨)

画像を1ユニットずつ生成しないでください。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

バッチ生成する理由:スタイルの一貫性を保つためです。単一ユニットごとに場当たり的に生成すると、スタイルにばらつきが生じます。同じスタイルの接頭辞を使ってバッチ生成すれば、統一感のあるビジュアルシステムを構築できます。

検証

検証には、それぞれ専用のスキルがある2つの観点があります。

  • 「参照されているアセットはディスク上に存在するか?」(ファイル間の参照チェック)→ web-content-audit を実行します。Audit 1(Cross-Artifact Reference Resolution)とアセットカバレッジ監査で、これを正確に確認できます。
  • 「アセットはブラウザーで404エラーなく実際に表示されるか?」(実行時チェック)→ web-visual-verification を実行します。console.error を収集する複数ビューポート対応の検証スクリプトを使えば、壊れた <img> リクエストを自動的に検出できます。

デプロイの前に、両方を実行してください。監査では存在しないファイルへの参照を検出し、検証ではファイルは存在するものの、レンダリングされたHTMLでパスが間違っているアセットを検出します。失敗する原因が異なるため、それぞれ別のスクリプトが必要です。

アンチパターン

  • スタイルの一貫性を保たずに画像を1点ずつ生成する — スタイル仕様を一度作成し、すべてのプロンプトの接頭辞として貼り付けます。
  • 画像にAI生成テキストを含める — ほとんどの場合、正しく表示されません。正確なテキストが必要な画像にはSVGを使います。
  • AI生成PNGのSVGフォールバックがない — PNGへのリンクが切れる(ファイルの削除や名前の変更ミスなど)と、サイトに画像切れアイコンが表示されます。SVGフォールバックがあれば、問題を最小限に抑えられます。
  • 再スクレイピング用スクリプトを用意せずにスクリーンショットを保存する — 6か月後に誰かが最新のスクリーンショットを必要としても、元のスクリーンショットをどう取得したか記録が残っていません。

引き継ぎ

ユーザーに次のように伝えます:「ビジュアルアセットを配置しました。node scripts/verify-assets.mjs を実行して不足がないことを確認してください。サイトはこれで機能完成です。次のステージ(course-ebook-publishing)では、同じコンテンツをPDF/DOCX形式の成果物にできます。ウェブ版が安定してからのみ実行してください。」

コメント