Communitygithub.com

takumifukasawa/agent-skills

從實際執行的遊戲中截取 Google Play 商店所需的宣傳素材:精準的促銷圖片 (1024x500)、真實手機/平板螢幕截圖,以及商店文案(簡短/完整描述)。適用於要求「製作商店圖片/素材/Play商店截圖/促銷圖片/商店描述」等場景,也支援大量遊戲畫面截圖供挑選。

agent-skills 是什麼?

這項技能可自動化 Google Play 商店素材的製作流程,直接從本地執行的遊戲中捕捉真實畫面,而非使用模擬圖。它產出三種素材:符合商店規格的螢幕截圖(支援批次處理與多種螢幕方向)、1024x500 的促銷圖片(可選擇全出血遊戲畫面或加上標題的合成版本),以及根據官方規範撰寫的商店文案。技能內建一個「挑選頁面」(Picker page),讓使用者能透過勾選框、圖片預覽與文字複製按鈕,從大量候選素材中輕鬆挑選最終組合,並包含備註功能供使用者提供修改意見。主要支援 Phaser、PixiJS、Three.js 及原生 Canvas 遊戲,需搭配 Playwright 與 Chromium 執行,並透過超取樣技術避免畫面鋸齒。此技能也與 `game-icon-from-screenshot` 技能互補,可將應用程式圖示納入同一個挑選流程。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/takumifukasawa/agent-skills/tree/HEAD/gamedev/game-store-assets

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

從執行中的遊戲產出商店素材

透過捕捉實際執行的遊戲畫面(而非模擬圖)來產出精確的商店素材。 可重複使用的腳本位於 scripts/;您只需提供少量的遊戲專用設定 (網址、就緒檢查、如何安排/隱藏/驅動遊戲、標題文字)。

三個產出項目:

  1. 螢幕截圖(scripts/screenshots.cjs)— 批次產出符合商店尺寸的畫面。
  2. 促銷圖片 — 1024x500 的宣傳橫幅:可為乾淨的全出血遊戲畫面 (screenshots.cjs 搭配橫向 target)或畫面加標題的合成圖 (scripts/feature_graphic.py)。詢問使用者偏好;預設為全出血 畫面(適合氛圍導向的遊戲)。
  3. 商店文案 — 簡短 + 完整描述:請參閱 references/listing-text.md(字數限制、語氣、禁止聲明、 「AI 生成素材」表單問題)。

關於商店尺寸需求與預設值,請參閱 references/play-store-sizes.md。

工作流程:大量候選 → 使用者挑選

使用者決定;您提供多樣性並讓挑選過程輕鬆。

  1. 每個關卡/等級/主題拍攝大量畫面(例如 5 個關卡 × 8–10 張)。 同時利用遊戲的進度來變化(初期/中期/後期升級階段): 初期畫面看起來空曠,後期可能遮蔽主體。
  2. 初選約 15 張具多樣性的畫面(每個關卡;過關/爆發時刻;豐富 vs 平靜 背景)。先用 scripts/contact_sheet.py 自己看過(已編號)。然後讓使用者選擇 — 在挑選頁面(見下方)中(當 Artifact 可用時,使用者看過後都會要求使用);否則傳送已編號的縮圖並接受數字選擇。
  3. 推薦一組,並說明理由(顏色/關卡多樣性,不重複相同時刻)。根據使用者 的意見重新拍攝(例如「被寫体をもう少し中央に」),並將重拍的照片 以同一個選取鍵新增到挑選頁面中。
  4. 將最終選定的檔案複製到一個資料夾中,依上傳順序排列(1-…png、2-…), 並將決定記錄在專案文件中(檔案名稱、選擇的文字、拒絕的選項及原因、 如何拍攝)。除非專案已追蹤商店素材,否則不要將產生的圖片納入 Git。

python3 ${CLAUDE_SKILL_DIR}/scripts/contact_sheet.py sheet.png a.png b.png … --cols 5 --thumb 300 (基礎的 Playwright/canvas 技術與 game-icon-from-screenshot 共用。)

挑選頁面 (Artifact):使用者勾選組合

python3 ${CLAUDE_SKILL_DIR}/scripts/build_picker.py picker.json picker.html,然後使用 Artifact 工具發佈 picker.html,並搭配 capabilities: {"db": {}}(請先載入 artifact-design / artifact-capabilities 技能,因為 Artifact 工具需要)。規格格式位於 scripts/build_picker.py 的開頭。

頁面功能(皆來自規格,範本中無遊戲專用內容):

  • 圖片群組 — mode: "multi"(螢幕截圖:勾選順序 = 上傳順序, ← → 可重新排序,max)或 "single"(促銷圖片、應用程式圖示)。多個群組可以共用一個 pick 鍵(初次候選 + 重拍 = 一個選擇)。 來自 rec 的「おすすめ」標記,⤢ 可縮放,頂端顯示所選組合的托盤, 以及「おすすめで埋める」按鈕。
  • 文字群組 — 包含提交文字的單選選項、下方的翻譯、 相對於 limit 的字數統計,以及每個選項右上角的複製按鈕(僅複製提交文字)。
  • 備註作為指示 — 每個群組一個備註框(noteKey)加上一個整體的 「全体への指示」。使用者可在其中撰寫指示(例如「2 案目の最後の行は いらない」,一份待編輯和翻譯的日文草稿)並說「保存しました」。
  • 選擇 — 小型的是/否單選按鈕(是否在促銷圖片上顯示標題文字)。
  • 所有內容都儲存在一個資料庫文件中(doc,預設為 picks/current);使用 ArtifactData 讀取(action: "get", collection: "picks", doc_id: "current" 為預設值)。選取/選擇/備註鍵共享該文件,因此建構器會拒絕衝突的鍵和重複的項目 ID。 當使用者說他們已儲存時,處理每一個非空的備註,然後告訴他們 變更了什麼。要更改頁面,請編輯規格並重建,然後 發佈相同的檔案路徑(相同的 URL;已儲存的選擇因為 ID 保持不變而得以保留)。 首次發佈後,讀取一次 picks 以確認商店答案。

應用程式圖示使用相同的頁面:一個僅圖示的挑選器(一個 "single" 群組, aspect: "1/1",thumbWidth: 512)或將圖示作為商店圖片旁的另一個群組。 使用 game-icon-from-screenshot 製作候選圖示。

先決條件

  • 遊戲在本地網址執行(npm run dev → 例如 http://localhost:5173)。
  • Playwright + Chromium(自動從專案 node_modules、npx 快取、 或全域解析;否則執行 npx playwright install chromium)。
  • Pillow(python3 -m pip install Pillow)用於調整大小/合成。
  • 一個用於促銷圖片標題的字型檔案(.ttf;支援可變字型的權重軸)。

抗鋸齒:超取樣,不放大

以精確輸出尺寸拍攝會產生鋸齒。請高密度拍攝後再降頻: 設定 superSample(deviceScaleFactor)為 2,讓腳本降頻到 目標尺寸。重要:使用 superSample 來提高密度,不要透過使用 更大的視口 — 過大的畫布會阻塞無頭渲染/物理迴圈 (遊戲會在生成時凍結)。保持視口在遊戲實際可玩的尺寸(例如 1080x1920),並提高 superSample 取代。

螢幕截圖

node ${CLAUDE_SKILL_DIR}/scripts/screenshots.cjs <config.(cjs|json)> [outDir]

  • 靜態擺拍(shots):每個開啟一個新頁面,執行您的 pose 函式(設定分數、定位主體、顯示結果覆蓋層…),可選擇隱藏 HUD,然後拍攝。適用於準備/結果畫面。
  • 即時遊戲(live):開始遊戲,每次輪詢執行您的 keepAlive 函式 以保持遊戲活動/驅動(一個「自動駕駛」),並在您的 pick 函式判斷畫面良好時拍攝。即時畫面顯示真實的動態/軌跡 — 這是 獲得「實際遊玩」畫面的方法,而非靜態畫面。拍攝大量, 讓使用者選擇。

fn 欄位在頁面中執行。在 .cjs 設定檔中撰寫真正的函式(它們會以 .toString() 序列化,因此請保持自包含 — 不要使用 Node 閉包)。 在 .json 設定檔中撰寫箭頭函式的原始碼字串。

  • 定時(timed):適用於可以自動播放的遊戲(例如 ?autoplay= 查詢參數、展示/吸引模式)。依序開啟每個網址,並每隔 intervalMs 毫秒 拍攝一次 — 這是獲得每個關卡大量真實畫面的最簡單方法。

設定(螢幕截圖)

url、ready、target {width,height}(輸出尺寸 + 視口)、viewport (當需要不同尺寸時的拍攝尺寸;畫面會裁切至目標比例, cropY 錨定頻帶)、superSample(2)、launchArgs、executablePath、 css(注入用於隱藏 DOM HUD 的最簡單方式)、routes [{match, replace: [[from,to]…]}](僅限拍攝時對提供來源的修補)、waitFontsReady (true)、hudHide(函式)、shots [{name, pose?, hideHud?, settleMs?}]、live {count, start, keepAlive, pick, hideHud, buildMs, pollMs, settleMs, maxTries, prefix}、timed {urls: [{prefix, url}], count, warmupMs, intervalMs}、 outDir。完整欄位文件位於 scripts/screenshots.cjs 的開頭。

Playwright 必須可解析:從包含 node_modules 的目錄執行,或使用 NODE_PATH=<dir>/node_modules node ${CLAUDE_SKILL_DIR}/scripts/screenshots.cjs …(CommonJS)。如果 安裝的瀏覽器比套件舊,腳本會退而使用 ms-playwright 快取中最新的 Chromium。

範例 (WebGL / three.js, 自播放, DOM HUD)

{
  "target": {"width": 1080, "height": 1920},
  "viewport": {"width": 540, "height": 960},
  "superSample": 2,
  "launchArgs": ["--use-angle=swiftshader", "--enable-unsafe-swiftshader"],
  "css": "body > div:not(#app) { display: none !important; }",
  "timed": {
    "urls": [{"prefix": "stage1", "url": "http://localhost:5173/?level=1&autoplay=1"},
             {"prefix": "stage2", "url": "http://localhost:5173/?level=2&autoplay=1"}],
    "count": 10, "warmupMs": 3000, "intervalMs": 3500
  }
}

全出血 1024x500 橫幅,適用於僅直向的遊戲(它在寬視口中使用信箱模式, 且其世界範圍超出直向視口):僅為此次拍攝解除比例限制,以 2 倍拍攝一個 較方正的視圖,然後裁切頻帶。

{
  "target": {"width": 1024, "height": 500},
  "viewport": {"width": 820, "height": 640},
  "superSample": 2,
  "launchArgs": ["--use-angle=swiftshader", "--enable-unsafe-swiftshader"],
  "css": "body > div:not(#app) { display: none !important; }",
  "routes": [{"match": "GameConfig", "replace": [["maxAspect: 0.6", "maxAspect: 0"]]}],
  "timed": {"urls": [{"prefix": "banner", "url": "http://localhost:5173/?level=1&autoplay=1"}],
            "count": 6, "warmupMs": 3000, "intervalMs": 5000}
}

範例 (Phaser, 直向; 開發者暴露 window.__game)

一個實際範例,來自一個特定的遊戲(球穿環遊戲)。請替換為您自己的 場景/物件名稱、擺拍邏輯和驅動/選取條件。

// phone.shots.cjs
const G = () => window.__game.scene.scenes[0]; // 頁面內輔助函式(下方內聯)
module.exports = {
  url: "http://localhost:5173/",
  target: { width: 1080, height: 1920 },
  superSample: 2,
  ready: () => !!(window.__game?.scene?.scenes?.[0]?.ring),
  hudHide: () => { const s = window.__game.scene.scenes[0]; ["scoreText","bestText","hintText"].forEach(k => s[k]?.setVisible(false)); },
  shots: [
    { name: "ready", hideHud: false },
    { name: "result", hideHud: true, settleMs: 1200, pose: () => {
        const s = window.__game.scene.scenes[0];
        s.matter.world.pause(); s.score = 18; s.highScore = 18; s.lastRunNewRecord = true; s.showResult();
    } },
  ],
  live: {
    count: 24, prefix: "play", pollMs: 45, buildMs: 700,
    startTap: true,            // 可信的點擊以開始(Phaser 忽略合成事件)
    hideHud: false,            // 在遊戲畫面中保留分數顯示
    start: () => { window.__game.scene.scenes[0].goals = 6; }, // 額外設定(例如啟用多樣性)
    keepAlive: () => { const s = window.__game.scene.scenes[0]; if (s.state === "playing" && s.ball.y > s.scale.height * 0.5) s.ball.setVelocityY(-13 * s.scaleFactor); },
    pick: () => { const s = window.__game.scene.scenes[0]; return s.state === "playing" && s.ball.body.velocity.y > 4; },
  },
};

平板組合:相同的設定,使用 target: { width: 1440, height: 2560 }。(您也可以 將選擇的手機截圖放大至 1440x2560,以保留完全相同的選定畫面。)

擺拍動畫(scripts/pose-capture.cjs)— 適用於 postFX/bloom 遊戲

live 模式假設遊戲的物理能在無頭模式下執行。但經常無法執行。一個 WebGL bloom / postFX 管線可能會阻塞無頭渲染+物理迴圈,使得 主體在其生成位置凍結(速度已設定但位置從未整合)— 每個「即時」 畫面看起來都一樣,主體卡在生成點。這在一個真實專案中造成了嚴重問題。 要檢查的症狀:在兩次輪詢中探測主體的 y 值;如果從未改變,則物理已停滯。

發生此情況時,請不要對抗它 — 手動驅動主體:

node ${CLAUDE_SKILL_DIR}/scripts/pose-capture.cjs <config.(cjs|json)> [outDir]

每個鏡頭會暫停世界,然後按照您定義的路徑,在 N 個影格上動畫主體(同時保持任何 軌跡/粒子發射器執行),因此無論物理如何,都會建立真實的運動軌跡。 每個鏡頭的設定:{name, setup, poseAt(t), steps, stepMs} — setup 執行一次並 將場景置於該鏡頭的狀態(例如在一個球與閘門的遊戲中:生成閘門,state="playing",world.pause(), trail.start(),隱藏準備提示,設定分數), poseAt(t) 對於 t 在 [0..1] 範圍內定位主體。

如何讓擺拍的軌跡看起來像真實運動(範例遊戲的主體在重力下下落;請根據您的遊戲如何移動來調整):

  • 貝茲曲線,非直線 lerp。 直線路徑會產生僵硬的直線 軌跡;一個帶有橫向控制點偏移的二次貝茲曲線會產生 遊戲實際產生的自然弧形。根據不同鏡頭變化曲線。
  • Ease-in t*t(加速)看起來像重力。
  • 適度提高發射器強度僅限此鏡頭(更高的 frequency + 更長的 lifespan),因為手動動畫比真實快速下降慢,且預設發射器會留下 過少的粒子。請適度提高 — 過度增強效果的軌跡看起來完全不像遊戲。

促銷圖片

python3 ${CLAUDE_SKILL_DIR}/scripts/feature_graphic.py <config.json>

合成:深色背景 → 真實遊戲截圖(左側,霓虹框)→ 標題 + 標語(右側,使用內建字型)→ 強調線條。以 superSample 倍渲染後降頻。

設定:out、size([1024,500])、superSample(2)、screenshot、font、 title、tagline、bg、frameColor、titleColor、titleGlow、tagColor、 accentColor、titleWeight、tagWeight。

以下範例值來自一個特定遊戲 — 請替換為您自己的標題、標語、顏色和字型。

{
  "out": "store-assets/feature-graphic-1024x500.png",
  "screenshot": "store-assets/feature-shot.png",
  "font": "public/fonts/Orbitron.ttf",
  "title": "MY GAME", "tagline": "ONE-TAP ARCADE",
  "bg": "#0a0a1c", "frameColor": "#27e6ff",
  "titleColor": "#ffffff", "titleGlow": "#27e6ff", "tagColor": "#8fffe0", "accentColor": "#27e6ff",
  "titleWeight": 800, "tagWeight": 600
}

經驗教訓(請務必遵守)

  • 無頭模式下的 WebGL 需要 SwiftShader。 如果不使用 --use-angle=swiftshader --enable-unsafe-swiftshader,three.js 的 canvas 會是 黑色的。它速度很慢:請一次只開啟一個頁面(5 個並行 WebGL 頁面會導致 截圖呼叫超時)。
  • 使用 CSS 隱藏 HUD:不要隱藏 canvas 的父容器。 一個全域的 div { visibility: hidden } 也會隱藏 canvas(每個畫面都相同,約 8 KB)。 請探查 DOM 一次,並透過 ID 排除 canvas 的包裝器。相同的小檔案 = 沒有任何渲染內容。
  • 僅支援直向的遊戲與橫向橫幅。 最大比例限制會將寬視口以信箱模式顯示 (中間一個狹窄的欄位)。請透過 routes 在拍攝時解除此限制;遊戲檔案可能 為 WebGL 快取所困擾,因此完整的頁面重新載入(使用 url 中的隨機查詢參數) 是必要的。
  • 手機截圖 = 先處理解析度。 使用 superSample: 2 使用較小的視口(540x960), 而不是試圖在 1080x1920 的視口播放遊戲(大多數 WebGL 遊戲無法在 合理的幀率下渲染 200 萬像素)。縮小視口並使用 superSample。
  • Chrome 127+ 需要 --disable-gpu-vsync。 如果動畫在幾秒鐘後停止, 請將此參數加入 launchArgs。
  • scripts/screenshots.cjs 中的 fn 欄位會在頁面中序列化。 在 .cjs 設定檔中 不要依賴來自 require 的 Node 變數;改使用字串取代、查詢參數或 遊戲的全域變數(例如 window.__game)。

增益集指令碼

遊戲邊界色票

python3 ${CLAUDE_SKILL_DIR}/scripts/game_palette.py <image> [--count 8] [--out palette.png]

從遊戲截圖中取樣主要顏色(用於促銷圖片的主題顏色)。使用 K-Means 聚類。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相關技能