見出し画像

Claude CoworkにCanvaのコネクタがあったので使ってみたら可能性の塊だった

ClaudeのCanvaコネクタに可能性を感じています。ただし、いきなり試すとほぼ100%「使えね〜」ってなっちゃうので、どんなことができるかを具体的に解説して、わたしが作ったバナー制作用のSkillsも共有します。

無料エリアでSkillsを配布しています。

こんにちは、ウミノです。まず左下の設定→コネクタ→注目→Canvaを選んでCanvaアカウントと連携しておいてください。

Canva連携でできることは?

一応聞いてみた。

デザインの検索・閲覧

  • Canva上のデザイン(プレゼン、ドキュメント、動画、ホワイトボードなど)をキーワードで検索

  • デザインの中身(テキスト内容)を読み取る

  • ページのサムネイルを確認する

  • フォルダの中身を一覧表示

デザインの新規作成

  • プレゼン、ポスター、SNS投稿、ドキュメント、チラシ、名刺、ロゴなど25種類以上のデザインをAI生成

  • プレゼンはアウトライン確認→生成の流れで丁寧に作れる

  • ブランドキットを適用して統一感のあるデザインも可能

既存デザインの編集

  • テキストの書き換え・部分置換

  • 画像や動画の差し替え・挿入・削除

  • テキストの書式変更(色、サイズ、太字、配置など)

  • デザインタイトルの変更

  • 要素のリサイズや位置調整

エクスポート・その他

  • PDF、PNG、JPG、PPTX、GIF、MP4などへの書き出し

  • デザインのリサイズ(別フォーマットへの変換)

  • コメントの閲覧・投稿・返信

  • 外部URLから画像をCanvaにアップロード

  • 外部ファイル(PDFなど)をCanvaデザインとしてインポート

  • フォルダの作成・アイテムの移動

とのこと。

Udemy AIコースのセールバナーを作らせてみた

わたしはUdemyでAIコースを出しているんですが、先日新コースリリース記念で全コース1300円セール中だったので、そのバナーを作ってと指示してみました。

最初こんなだっさいの出してきたのでちょっとがっかり。

ほんとにCanva使ったのかと聞いてみたら、Canvaのツールを使ったけど、なんかAI画像生成ではないと言ってる。

CanvaのAI画像生成を使って、と再度指示をしたら、Canva開いてアプリで画像生成しだしました。

おおおサイズ変更してる!!!

テキスト入力してる!!!

ちょいちょい許可を求められます。ちょっとめんどうです。

あああしかも会話が圧縮されてる…トークン消費激しそう。これはちゃんとSkill化(手順化)したほうがよさそうです。

ダウンロードに苦戦してましたが、なんとかダウンロード完了!

作られたバナーはこちら!じゃじゃ〜ん。はい、ダサいですね。バナーですらない。でもここで諦めたら試合終了ですよ。

この試行錯誤をもとに、わたしは学びました。

今のClaude✕Canvaでは、デザインを一からやらせるのはムリだ。

なので次に試したのは、自分で作ったデザインをもとにテキストだけ変更させるという方法。

既存デザインをもとに微修正させる→成功

まず、Canvaでこういうデザインを作りました。

で、マルで囲ったところだけを変更します。

めちゃくちゃ試行錯誤してましたが、最終的に成功しました!完成したバナーがこちら👇️割とよくない?

>>実際にAIコース1500円セールしてます

作ったスキルはこちら

---
name: canva-sale-banner-update
description: |
  Canvaの「Udemyセール告知」デザインの金額・日付・OFF率を更新し、PNGでダウンロードするスキル。
  「セール告知更新」「Udemyセール画像」「セールバナー更新」「告知画像を更新」
  「Canvaのセール告知」「クーポン画像更新」「セール告知PNG」などの発言があれば使用する。
  3つの要素(金額・日付・OFF率)が指定されていない場合は必ずユーザーに確認する。
---

# Canva Udemyセール告知バナー更新スキル

## 概要

Canvaの「Udemyセール告知」デザインの3要素(金額・日付・OFF率)をCanva MCP APIで更新し、PNGファイルをエクスポートする。

## 前提条件

- Canva MCP コネクタが接続済みであること

## 必須パラメータ(3つ)

以下の3つが **すべて揃っていない場合は、AskUserQuestion で必ず確認する**。推測で埋めない。

| パラメータ | 例 | 説明 |
|-----------|------|------|
| 金額 | 1500円 | 「全コース○○円」の数字部分 |
| 日付 | 3/31まで | 「○/○○まで」の形式 |
| OFF率 | 94% | 「○○% OFF」の数字部分 |

### 確認テンプレート

3つのうち1つでも欠けている場合、AskUserQuestion で以下を聞く:


セール告知バナーを更新します。以下の3つを教えてください:
・金額:全コース○○円(例:1500円)
・日付:○/○○まで(例:3/31まで)
・OFF率:○○%(例:94%)


## 実行手順

### STEP 1: デザインを検索する


search-designs(query: "Udemyセール告知")
→ design_id を取得


見つからない場合はユーザーにデザイン名またはURLを確認する。

### STEP 2: 編集トランザクションを開始する


start-editing-transaction(design_id)
→ transaction_id と全テキスト要素(richtexts)を取得


**"Access token is invalid" エラーが出た場合:**
suggest_connectors でCanvaコネクタの再接続を案内 → ユーザーが再接続したらリトライ

### STEP 3: テキスト要素を特定して一括更新する

richtexts の中から以下3つの要素を **テキスト内容で特定** する:

| 対象 | 特定方法 | 置換テキスト |
|------|----------|------------|
| 金額 | `text` に「全コース」を含む要素 | `全コース{金額}円` |
| 日付 | `text` に「まで」を含む要素 | `{日付の数字部分}\nまで` |
| OFF率 | `text` が数字2〜3桁のみの要素("OFF"や"%"とは別要素) | `{OFF率の数字部分}` |

**要素特定の注意点:**
- 金額テキストは過去編集の残りで値が重複していることがある(例:「全コース1500円全コース1300円」)。replace_text で丸ごと置換すれば問題ない
- 「%」「OFF」「最大で」はそれぞれ別要素。変更しない
- 日付は改行(`\n`)で「3/31」と「まで」が分かれている構造

3つの編集を **perform-editing-operations で一括実行** する:

json
{
  "operations": [
    {
      "type": "replace_text",
      "element_id": "{金額の要素ID}",
      "text": "全コース1500円"
    },
    {
      "type": "replace_text",
      "element_id": "{日付の要素ID}",
      "text": "3/31\nまで"
    },
    {
      "type": "replace_text",
      "element_id": "{OFF率の要素ID}",
      "text": "94"
    }
  ]
}


### STEP 4: プレビュー確認と保存

1. STEP 3 のレスポンスに含まれるサムネイルをユーザーに表示する
2. 問題なければ `commit-editing-transaction` で保存する
3. 問題があれば `cancel-editing-transaction` でキャンセルし、修正してリトライ

### STEP 5: PNGエクスポート


export-design(design_id, format: { type: "png" })
→ ダウンロードURLをユーザーに提示


export-design でもトークンエラーが出る場合は、Canvaコネクタ再接続を案内してリトライ。

## エラーハンドリング

| エラー | 対処 |
|--------|------|
| Access token is invalid | suggest_connectors でCanvaコネクタ再接続を案内 → リトライ |
| デザインが見つからない | デザイン名・URLをユーザーに確認 |
| テキスト要素が特定できない | richtexts の全要素をユーザーに提示して確認 |
| commit / export 失敗 | コネクタ再接続 → リトライ |

## 成功条件

- [ ] 金額・日付・OFF率の3要素がすべて正しく更新されている
- [ ] プレビューサムネイルでユーザーが確認済み
- [ ] PNGファイルがエクスポートされている

デザインはまきもさんのこちらをほぼそのまま使わせていただきました⭐️

ちなみにこの記事のサムネイル画像はこう作ってます

記事のサムネイル画像もCoworkで作ってます。ただ、実はCanvaコネクタは使っていません。HTML・CSSで作らせて、それをPNGでエクスポートさせています。

なぜかというと「フォントの大きさを画像の横幅ギリギリまで攻める」といったことが、Canvaを使うと難しいからです。

これを作るスキルはこちら👇️👇️👇️

---
name: thumbnail-generator-light
description: |
  YouTube/SNS用のインパクトサムネイルを生成するスキル(軽量版)。
  21:9(1470×630px)の背景にシステムデフォルトフォント(太字)でテキストを最大サイズ配置。
  フォントファイル同梱不要。環境を選ばず動作する。
  「サムネ作って」「サムネイル生成」「thumbnail」「YouTubeサムネ」
  「タイトル画像を作って」などの発言があれば使用する。
  1〜3行のテキストに対応。背景色・文字色の変更も可能。
---

# Thumbnail Generator Light

21:9(1470×630px)のサムネイル画像を生成する。
黒背景 × ブラウザデフォルトフォント(太字)× 最大フォントサイズで、インパクト重視のデザイン。

**thumbnail-generator との違い:** フォントファイル(NotoSerifJP-Black.ttf)を同梱しない。
システムフォントを使うため、スキルのサイズが軽量で環境依存が少ない。

## 前提条件

- Playwright(Python)がインストール済みであること

### Playwright未インストールの場合

bash
pip install playwright --break-system-packages
playwright install chromium


## 使い方

### Step 1: ユーザーからの情報収集

以下をAskUserQuestionで確認する(必須は1のみ):

1. テキスト内容(1〜3行。`/` で区切って指定されることが多い)
2. サイズモード(デフォルト: uniform)
   - `uniform`: すべての行が同じフォントサイズ(最も長い行に合わせる)
   - `variable`: 短い行を大きく表示して縦の余白を埋める
3. 背景色(デフォルト: `#000` 黒)
4. 文字色(デフォルト: `#fff` 白)

### Step 2: HTMLの生成

以下のHTMLを生成する。フォント指定は `sans-serif` のみ(font-weight: 900)。

html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
  width: 1470px;
  height: 630px;
  background: {{BG_COLOR}};
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
#container {
  width: 1420px;
  height: 620px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.line {
  font-family: sans-serif;
  font-weight: 900;
  color: {{TEXT_COLOR}};
  line-height: 1.0;
  letter-spacing: -0.01em;
  white-space: nowrap;
  text-align: center;
}
</style>
</head>
<body>
<div id="container">
</div>
<script>
const lines = {{LINES_JSON}};
const mode = "{{MODE}}";
const containerW = 1420;
const containerH = 620;
const correction = 0.88;

const container = document.getElementById('container');

const els = lines.map(text => {
  const el = document.createElement('div');
  el.className = 'line';
  el.textContent = text;
  el.style.fontSize = '100px';
  container.appendChild(el);
  return el;
});

document.fonts.ready.then(() => {
  if (mode === 'uniform') {
    let maxRatio = 0;
    els.forEach(el => {
      const w = el.getBoundingClientRect().width;
      const ratio = w / 100;
      if (ratio > maxRatio) maxRatio = ratio;
    });
    let fontSize = (containerW / maxRatio) * correction;
    const totalH = fontSize * 1.0 * lines.length;
    if (totalH > containerH) {
      fontSize = (containerH / lines.length) * correction;
    }
    els.forEach(el => {
      el.style.fontSize = fontSize + 'px';
    });
  } else {
    const sizes = els.map(el => {
      const w = el.getBoundingClientRect().width;
      const ratio = w / 100;
      return (containerW / ratio) * correction;
    });
    const totalH = sizes.reduce((a, b) => a + b, 0);
    if (totalH > containerH) {
      const scale = containerH / totalH;
      sizes.forEach((s, i) => {
        els[i].style.fontSize = (s * scale) + 'px';
      });
    } else {
      sizes.forEach((s, i) => {
        els[i].style.fontSize = s + 'px';
      });
    }
  }
});
</script>
</body>
</html>


プレースホルダの置換:

| プレースホルダ | 内容 | 例 |
|---|---|---|
| `{{BG_COLOR}}` | 背景色 | `#000` |
| `{{TEXT_COLOR}}` | 文字色 | `#fff` |
| `{{LINES_JSON}}` | テキスト行のJSON配列 | `["1行目", "2行目"]` |
| `{{MODE}}` | サイズモード | `uniform` or `variable` |

### Step 3: Playwrightでキャプチャ

python
import asyncio
import os
import tempfile
from playwright.async_api import async_playwright

async def capture_thumbnail(html_content, output_path):
    with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
        f.write(html_content)
        tmp_html = f.name
    try:
        async with async_playwright() as p:
            browser = await p.chromium.launch()
            page = await browser.new_page(viewport={"width": 1470, "height": 630})
            await page.goto(f"file://{tmp_html}", wait_until="networkidle")
            await page.wait_for_timeout(2000)
            await page.screenshot(path=output_path, type="png")
            await browser.close()
    finally:
        os.unlink(tmp_html)


### Step 4: 出力と確認

- 出力先: ユーザーのワークスペースフォルダ
- ファイル名: ユーザー指定がなければ `YYYYMMDD_thumbnail.png`
- 生成後、Readツールで画像を表示してユーザーに確認

## 技術仕様

### サイズ計算ロジック

1. 各行のテキスト幅を100pxの基準サイズで計測
2. `uniform` モード: 最も長い行に合わせて全行同じサイズを算出
3. `variable` モード: 各行を横幅いっぱいに独立してサイズ算出 → 合計が高さを超える場合は比率で縮小
4. 補正係数 `0.88` を掛けて、フォントの太さによるはみ出しを防止

### 固定パラメータ

- 画像サイズ: 1470×630px(21:9)
- パディング: 上下5px、左右25px
- line-height: 1.0
- letter-spacing: -0.01em
- フォント補正係数: 0.88
- フォント: `sans-serif`(システムデフォルト、weight: 900)

## 注意事項

- テキストが4行以上になるとフォントサイズが小さくなりすぎるため、3行以内を推奨
- 英数字と日本語が混在する場合、英数字の方が細いためバランスが変わることがある
- フォントの見た目は実行環境のシステムフォントに依存する(明朝体にはならない)
- 背景画像を入れたい場合は、HTMLテンプレートの `body` に `background-image` を追加する(別途対応)

ただし、実はこの方法だとフォントがいまいちだったり文字化けしちゃうこともあります。うまくやるやり方は最後のnoteメンバーシップエリアで解説します👇️👇️

Cowork✕Canvaでできること

では、今日のおさらい。ぶっちゃけ、CoworkとCanvaでできること、現時点では多くないです。コネクタでできることで、実務に使えるのはこのあたり。

・既存のデザインを探すこと ・デザインのテキストや文字の大きさを変えること ・作ったデザインをDLすること

コネクタ(API経由)ではなくClaude in Chrome(画面操作)をすればもっといろいろできます。たぶんだいたいのことはできる。無限に時間とトークンがあれば。

現実的にはある程度デザインとそれに合ったスキルを作っておいて、そのとおりに動かすという、今回のやり方が現状の最適解かと思っています。

CoworkのスキルとCanvaのデザインをセットにして販売とかしたら、稼げる気がする。やりたい人、ぜひやってみてください。

無料のCoworkセミナーやります

3/19(木)21時から無料のCoworkセミナーをやるので、予定あけておいてくださいね。

無料セミナー申し込みはこちら


いい感じのフォントでテキストベースのサムネイルを作る方法

それはズバリ、

ここから先は

3,678字 / 3画像
この記事のみ ¥ 2,480
Amazon Payで支払うと最大2%還元のチャンス! 9/30まで

仕事・育児・家事などで毎日時間に追われ、「やりたいことはある・今の忙しさを改善したいのに考える余裕が…

オプティマイザー

¥1,980 / 月

オプティマイザー法人版

¥29,800 / 月

アルティメット

¥100,000 / 月
あと9人募集中