screen-recording について
Screen Recordingは、UI操作やデスクトップアプリ、ワークフローのアニメーションGIFを作るスキルです。フレームの取得、表示時間の調整、注釈を組み合わせ、ドキュメントやPR、リリースノートに使えます。
主な機能
- 01Playwrightによるブラウザフレーム取得
- 02mssによるデスクトップ領域の録画
- 03imageioによるGIFの組み立て
- 04フレーム表示時間の個別設定
- 05注釈の追加とフェード表示
活用シーン
- 01PRで複数段階のUI操作を提示
- 02動作変更の前後を記録
- 03バグの再現や修正を説明
- 04注釈付きのリリース紹介を作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill screen-recordingインストール後、Claude Code で/screen-recordingを入力して読み込まれたか確認します。
詳細
画面録画
機能やワークフローの動作を、注釈や可変のタイミング、適切なテンポで示すアニメーション GIF のデモを作成します。PR の説明、ドキュメント、リリースノートに役立ちます。
このスキルを使うタイミング
次のような場合にこのスキルを使います。
- 複数ステップの UI 操作をアニメーション GIF として録画する
- 動作の変更前と変更後を示すデモを作成する
- ドキュメントやリリースノート用の注釈付きチュートリアルを作成する
- バグの再現や修正の様子を示す
前提条件
pip install playwright Pillow imageio numpy scipy mss -q
playwright install chromium
基本的なワークフロー
1. フレームをキャプチャする
Playwright を使って操作を進め、各フレームをキャプチャします。
from playwright.async_api import async_playwright
async def record_frames(url, steps, width=1400, height=900):
"""
steps: list of dicts with 'action' (async callable taking page)
and 'name' (frame filename)
"""
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page(viewport={"width": width, "height": height})
await page.goto(url, wait_until="networkidle")
for step in steps:
if step.get("action"):
await step["action"](page)
await page.wait_for_timeout(step.get("wait", 500))
await page.screenshot(path=step["name"])
await browser.close()
2. imageio で GIF を組み立てる
GIF の書き出しには PIL ではなく imageio を使ってください。PIL の GIF エンコーダーは見た目が似たフレームを統合するため、アニメーションが台無しになります。
import imageio.v3 as iio
from PIL import Image
import numpy as np
frames = []
durations = []
for frame_path, duration_ms in frame_list:
img = Image.open(frame_path)
frames.append(np.array(img))
durations.append(duration_ms)
iio.imwrite("demo.gif", frames, duration=durations, loop=0)
3. フレームの表示時間を変える
均一なタイミングでは、全体が速すぎたり遅すぎたりする印象になります。表示時間に変化をつけてください。
| フェーズ | 表示時間 | 理由 |
|---|---|---|
| 素早い操作(入力、クリック) | 100ms | 自然なテンポになり、活気を保てます |
| 操作後の一時停止 | 600-800ms | 視聴者が何が起きたかを理解する時間を確保できます |
| 重要なメッセージ/最後のメッセージ | 500ms+ | 主な要点を伝えるには時間が必要です |
4. フレームに注釈を付ける
image-annotations スキルを使って、特定のフレームに注釈を追加します。
from PIL import Image, ImageDraw, ImageFont
def annotate_frame(frame_path, annotations, out_path):
img = Image.open(frame_path)
draw = ImageDraw.Draw(img)
for ann in annotations:
# Apply annotation (rect, arrow, label, etc.)
pass
img.save(out_path)
5. 注釈をフェードインさせる
注釈を滑らかに表示するには、次のようにします。
def apply_fade(base_frame, annotation_layer, alpha):
"""Blend annotation onto frame at given alpha (0.0 to 1.0)"""
blended = Image.blend(
base_frame.convert("RGBA"),
annotation_layer.convert("RGBA"),
alpha
)
return blended.convert("RGB")
# 2-frame pop-in at 10fps: 50% then 100%
faded_frames = [
apply_fade(base, annotations, 0.5), # frame 1: half opacity
apply_fade(base, annotations, 1.0), # frame 2: full opacity
]
10fps ではフェード用のフレームを 2 枚使います(合計 0.2s)。30fps では 3~4 枚使います。低 FPS ではイージングカーブの見た目が悪くなります。シンプルにポップインさせる方がきびきびとして読みやすくなります。
スクリプトとして作成する
単純なデモを超えると、注釈のロジックは複雑になります。インラインコードではなく、関数を使った専用のスクリプト(例:annotate_gif.py)を作成してください。タイミングや配置を繰り返し調整できます。
アニメーションのテスト
必ず最初に単独でテストしてください。フェードを少し調整するためだけに、デモ全体を作り直してはいけません。
# Small test GIF: 10 bare frames → fade frames → 15 hold frames
# Add a frame counter overlay for debugging:
draw.text((10, height - 30), f"F{i}/{total} a={alpha:.0%} FADE",
fill="white", font=small_font)
デスクトップ画面の録画(mss)
デスクトップアプリ、ターミナル、またはブラウザー以外のものを録画する場合に使用します。高速な画面キャプチャには mss を使います。
import mss
from PIL import Image
import time
def record_gif(output_path, region=None, duration=5, fps=8):
"""Record screen region to GIF. region = {left, top, width, height} or None for full screen."""
with mss.mss() as sct:
if region is None:
region = sct.monitors[1] # primary monitor
frames = []
t_end = time.time() + duration
while time.time() < t_end:
t0 = time.time()
shot = sct.grab(region)
frames.append(Image.frombytes('RGB', shot.size, shot.rgb))
time.sleep(max(0, 1 / fps - (time.time() - t0)))
frames[0].save(output_path, save_all=True, append_images=frames[1:],
duration=int(1000 / fps), loop=0, optimize=True)
return len(frames)
record_gif('demo.gif', region={'left': 0, 'top': 0, 'width': 800, 'height': 500}, duration=3)
テスト結果:8fps で 3s → 24 フレーム、約 31KB。ファイルサイズを適切に保つため、fps は 10 以下にしてください。
注記: 単純な録画では PIL.save(save_all=True) が使えますが、見た目が似たフレームを統合します。フェード効果のある注釈付き GIF には、代わりに imageio.v3.imwrite を使ってください。
ウィンドウキャプチャとの組み合わせ
# Find window rect, then record it as a GIF
# Reuse find_window() from the ui-screenshots skill
import ctypes
from ctypes import c_int, Structure, byref, windll
class RECT(Structure):
_fields_ = [('left', c_int), ('top', c_int), ('right', c_int), ('bottom', c_int)]
hwnd = find_window('My App')[0][0]
rect = RECT()
windll.user32.GetWindowRect(hwnd, byref(rect))
region = {'left': rect.left, 'top': rect.top,
'width': rect.right - rect.left, 'height': rect.bottom - rect.top}
record_gif('app-demo.gif', region=region, duration=5, fps=8)
差分ベースのクラスタ検出
フレーム間で変化した領域をプログラムで検出し、注釈を付ける場所を決めます。
import numpy as np
from scipy import ndimage
def find_changed_clusters(frame_a, frame_b, threshold=30, min_pixels=300, dilate=5):
"""Find bounding boxes of changed regions between two frames."""
diff = np.abs(frame_b.astype(float) - frame_a.astype(float)).max(axis=2)
mask = diff > threshold
dilated = ndimage.binary_dilation(mask, iterations=dilate)
labeled, n = ndimage.label(dilated)
clusters = []
for i in range(1, n + 1):
ys, xs = np.where(labeled == i)
if len(ys) < min_pixels:
continue
clusters.append((xs.min(), ys.min(), xs.max(), ys.max(), len(ys)))
return sorted(clusters, key=lambda c: -c[4]) # largest first
形式の互換性
| 形式 | VS Code プレビュー | GitHub | ブラウザー |
|---|---|---|---|
| GIF | ✅ アニメーション表示 | ✅ | ✅ |
| WebP | ⚠️ 静止画のみ | ✅ | ✅ |
| MP4 | ❌ 動作しない | ⚠️ | ✅ |
VS Code のプレビュー、GitHub の Markdown、ブラウザーで共通してサポートされるアニメーション形式は、GIF だけです。
ガイドライン
- 入力 → 一時停止 → 注釈 — 素早い操作中は注釈を一切表示しません。まず一時停止し、その後で注釈を付けます
- 重要なメッセージには最大のフォントを使う — 主な要点には 64pt 以上、詳細には 38pt を使います
- GIF のパレットでグラデーションが損なわれることはありません — 20 段階の異なるアルファ値は、256 色のパレットでも維持されます
- 入力や操作には最低 10fps — これより低いとカクついて見えます
- 段階的に作成する — まずフレームの順序を整え、次に注釈を追加し、最後にタイミングを調整します
制限事項
- GIF は 1 フレームあたり 256 色に制限されます。UI のスクリーンショットには適していますが、写真のようなコンテンツではバンディングが発生することがあります
- 解像度が高くフレーム数の多い GIF(50 フレーム以上)は数 MB になることがあります。関連する領域だけを切り抜くことを検討してください
- GIF は音声に対応していません。音声付きのデモには MP4 を使ってください(ただし、VS Code のプレビューには対応しなくなります)