Skip to content

alu1006/ig-carousel

Repository files navigation

IG Carousel Generator

用 Next.js + Playwright 產生 1080×1080 的 Instagram carousel 圖片(封面 → 觀念 → 選擇題 → 解答 → CTA → 結尾),可直接透過 Graph API 發佈到 InstagramThreads

原本設計給 Python 教學用,但所有內容來自 src/data/carousel.json、品牌來自 src/data/brand.json,換主題只要改 JSON、換 logo,整個工作流可直接套用。

另附一個 Claude Code skill.claude/skills/ig-carousel/SKILL.md),在 Claude Code 環境下說「幫我做一篇關於 XXX 的輪播」,Claude 會自動跑完「生內容 → 寫文案 → 截圖 → 發佈」整個流程。


Features

  • Slide typescover / explanation / content(選擇題)/ answer / cta-question / end
  • 程式碼高亮:shiki,預設 Python,可改其他語言
  • Playwright 截圖:逐張輸出 PNG 到 output/<topic-slug>/
  • 一鍵發佈scripts/upload-ig.ts 呼叫 Instagram Graph API,自動處理圖床暫存 + carousel 子容器 + 發佈
  • Threads 發佈:流程文件在 skill 裡(.claude/skills/ig-carousel/SKILL.md Step 4-B)
  • 品牌抽離:所有品牌相關設定都在 src/data/brand.json,換人用只改一個檔

Prerequisites

  • Node.js 20+
  • 一個 Instagram Business 或 Creator 帳號(個人帳號不能用 Content Publishing API)
  • Meta Developers 帳號 + 一個 App(Business 類型)
  • 想發 Threads 的話:把 IG 帳號連到 Threads、並在同個 App 加 Threads 產品

初始設定

1. Clone & install

git clone <your-fork-url> ig-carousel
cd ig-carousel
npm install

2. 換品牌資料

從 example 複製一份你自己的 brand.json(已被 .gitignore,不會把你的品牌值推回公開 repo):

cp src/data/brand.example.json src/data/brand.json

然後編輯 src/data/brand.json

{
  "name": "你的品牌名",
  "logo": {
    "src": "/logo.png",
    "alt": "你的品牌",
    "coverWidth": 360,  // 封面頁 logo 尺寸
    "coverHeight": 99,
    "endWidth": 300,    // 結尾頁 logo 尺寸
    "endHeight": 83
  },
  "qrcode": {
    "src": "/qrcode.png",
    "width": 200,
    "height": 200
  },
  "social": {
    "instagram": "your_ig_username",
    "threads": "your_threads_username"
  },
  "endSlide": {
    "ctaTitle": "追蹤更多教學"
  }
}

然後把自己的 logo 和 QR code 放到 public/

public/
  logo.png      # 透明背景 PNG(會同時用在封面、結尾、浮水印)
  qrcode.png    # 指向你主要社群連結的 QR code

想改主色、字體、版面?改 src/components/slides/*.tsx。品牌資料(username / logo 尺寸 / CTA 文字)改 brand.json 就好,不要硬寫在組件裡。

3. 設定 .env

cp .env.example .env

編輯 .env 填入 token(取得方式見下一節):

# Instagram(IG Login API,IGAA 開頭 token)
IG_ACCESS_TOKEN=IGAA...
IG_USER_ID=17841400000000000

# Threads(若要發 Threads)
THREADS_ACCESS_TOKEN=THAA...
THREADS_USER_ID=12345000000000000

.env 已被 .gitignore,不會被 commit。


取得 Token(IG Login API / Threads API)

Instagram

  1. 前往 https://developers.facebook.com/apps,建立 Business 類型 App

  2. 左側 ProductsInstagramAPI setup with Instagram Login

  3. 1. Generate access tokens 區塊加入你的 IG 帳號並產生 token

    • 需要權限:instagram_business_basicinstagram_business_content_publish
  4. 複製產生的 long-lived token(IGAA 開頭)到 .envIG_ACCESS_TOKEN

  5. 取得 IG_USER_ID

    curl "https://graph.instagram.com/v21.0/me?fields=id,username&access_token=$IG_ACCESS_TOKEN"

    回傳 {"id":"27020...","username":"..."},把 id 填到 .env

⚠️ Token 60 天會過期。 過期前可以 refresh:

curl "https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=$IG_ACCESS_TOKEN"

過期後沒救,要重開後台重新產。建議變成月常規。

Threads

  1. 同一個 App 加 Threads 產品

  2. Threads → API Setup 產生 long-lived user token

  3. 取得 THREADS_USER_ID

    curl "https://graph.threads.net/v1.0/me?fields=id,username&access_token=$THREADS_ACCESS_TOKEN"

⚠️ IG user id 跟 Threads user id 不一樣(就算是同一個 username 也一樣),不能混用。.env 裡一定要分開放。


Usage

1. 編輯 src/data/carousel.json

(或用 Claude Code skill 自動生)

{
  "topic": "your-topic-slug",
  "slides": [
    { "type": "cover", "title": "...", "subtitle": "...", "tags": ["...", "..."] },
    { "type": "explanation", "title": "...", "body": "...", "points": ["..."], "code": { "language": "python", "content": "..." } },
    { "type": "content", "title": "...", "code": {...}, "question": "...", "options": ["A. ...", "B. ...", "C. ...", "D. ..."] },
    { "type": "answer", "title": "答案:B", "explanation": "...", "points": ["..."] },
    { "type": "cta-question", "title": "...", "code": {...}, "question": "...", "options": [...], "ctaText": "私訊回覆「答案」獲得解答" },
    { "type": "end" }
  ]
}

2. 啟 dev server

npm run dev

打開 http://localhost:3000/carousel 預覽全部頁面。

3. 截圖

npx tsx scripts/capture.ts

PNG 會輸出到 output/<topic-slug>/,檔名依序為 01-cover.png02-explanation.png、…。

4. 寫文案

output/<topic-slug>/caption.txt 寫好文案(IG / Threads 共用)。

⚠️ Threads 限制 500 字,IG 限制 2200 字。 文案結構建議:鉤子 → 內容摘要 → CTA → 分隔符 → hashtags。

Hashtag 區塊前務必加一個非空白字元(例如 )當分隔符——Threads API 實測會把「貼文開頭接 newline 的第一個 hashtag」的井字號吃掉。

5. 發佈到 Instagram

# 只建容器(24h 內可發佈)
npx tsx scripts/upload-ig.ts

# 建容器 + 立即發佈
npx tsx scripts/upload-ig.ts --publish

# 發佈之前建好的容器
npx tsx scripts/upload-ig.ts --publish <container_id>

腳本會把 output/<topic-slug>/*.png 先上傳到 litterbox.catbox.moe(72h 暫存)供 IG 伺服器抓取,然後建 carousel item → carousel container → publish。

6. 發佈到 Threads

目前沒有腳本,流程在 .claude/skills/ig-carousel/SKILL.md Step 4-B(手動 curl 流程)。核心差異:

  • Base URL 是 https://graph.threads.net/v1.0
  • 建 item 時 media_type=IMAGE 必填
  • 建 carousel container 時文案欄位叫 text,不是 caption

用 Claude Code 跑整個流程

本 repo 包含一個 Claude Code skill:.claude/skills/ig-carousel/SKILL.md

在 Claude Code 開啟本專案後,說:

「幫我做一張關於 Python list comprehension 的 carousel,封面標題 XXX,大綱 YYY ZZZ,發到 IG 和 Threads」

Claude 會自動:

  1. src/data/carousel.json
  2. caption.txt
  3. 啟 dev server + Playwright 截圖
  4. 把 carousel 發到 IG / Threads

整個流程的 prompt、踩雷提醒、token 驗證指令都在 skill 裡,fork 後不用再調教。


Troubleshooting

症狀 可能原因 / 解法
Object with ID 'xxx' does not exist IG_USER_IDTHREADS_USER_ID 用混了,或 token 對不到 user id
Invalid OAuth access token / 401 Token 過期(60 天),重開 Meta 後台產新的
upload-ig.ts 上傳到 litterbox 時 HTTP 429 Rate limit。手動用 tmpfiles.org 上傳剩下的圖、手動跑剩下流程(見 skill Step 4-A 踩雷提醒)
Threads 文案第一個 #hashtag 變純文字 已知 quirk:hashtag 區塊前要加一個非空白字元當分隔符
Media aspect ratio must be within... 圖片比例不在 4:5 ~ 1.91:1,檢查 slide 組件尺寸
截圖 fails / 空白 dev server 沒啟、或 port 不是 3000

專案結構

.
├── .claude/skills/ig-carousel/SKILL.md   # Claude Code skill(核心 prompt)
├── public/                                # logo.png、qrcode.png(自行替換)
├── scripts/
│   ├── capture.ts                         # Playwright 截圖
│   └── upload-ig.ts                       # IG 發佈
├── src/
│   ├── app/carousel/page.tsx              # 輪播預覽頁
│   ├── components/slides/                 # 各類 slide 組件
│   └── data/
│       ├── brand.json                     # 品牌設定(改這裡)
│       └── carousel.json                  # 當前輪播內容
├── output/<topic-slug>/                   # 截圖 + caption 輸出(gitignored)
└── .env.example                           # 環境變數範本

Security

  • .envoutput/scripts/ig_session*.json 都在 .gitignore,不會被 commit
  • Token 請不要 commit,也不要貼到 issue / PR
  • Token 洩漏請立刻到 Meta Developers 後台 invalidate

License

MIT. 隨便改隨便用,但發佈到的社群帳號的內容請自行負責。

About

Generate Instagram/Threads educational carousels with Next.js + Playwright + Claude Code skill

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors