メインコンテンツまでスキップ

Codex操作ログをGIFにする

要旨

ローカル Codex は、隔離された作業環境の中でコマンドを実行し、結果を確認できます。ただし、今回の検証環境では macOS 標準の screencapture は存在するものの、Codex 実行環境から実画面を直接撮影しようとすると could not create image from display で失敗しました。

そこで、記事素材として必要なものを「実画面そのもの」ではなく「実際に実行したコマンドとログを反映したターミナル画面風 GIF」と定義します。ログが実行結果に基づいているなら、環境構築記事の読者に伝える情報としては本物のキャプチャと同等に扱えます。

この方法の利点は、画面録画権限や録画ツールに依存せず、コマンド、出力、説明したいタイミングを制御できることです。GIF の生成には Pillow を使い、複数の画像フレームを save_allappend_images で連結します。Pillow の GIF 保存では、フレーム表示時間を duration、ループ回数を loop で指定できます。1

完成イメージ

Codexのコマンド実行結果を反映したターミナル画面風GIF

この GIF は、今回確認した以下の流れを 4 フレームに分けて描画しています。

  • 画面キャプチャ系コマンドと GIF 変換ツールの有無を確認する
  • screencapture が Codex 実行環境から失敗することを確認する
  • Pillow が使える Python で GIF を生成する
  • 生成された GIF の形式、サイズ、フレーム数を確認する

全体像

実画面を撮る工程を外し、コマンド実行ログを一次情報として使います。見せたいポイントだけをフレーム化するため、動画より短く、スクリーンショット連番より読みやすい素材になります。

今回確認した前提

まず、使えるコマンドとライブラリを確認しました。

$ command -v screencapture
/usr/sbin/screencapture

$ command -v ffmpeg
# no output

$ command -v magick
# no output

$ command -v gifsicle
# no output

結果は次の通りです。

確認項目結果使い方
screencapture存在するがCodexからの画面取得は失敗実画面キャプチャには使わない
ffmpeg未導入今回のGIF生成では使わない
ImageMagick未導入今回のGIF生成では使わない
gifsicle未導入今回のGIF生成では使わない
PillowCodex同梱Pythonで利用可能フレーム描画とGIF保存に使う

screencapture の確認では、次のように失敗しました。

$ screencapture -x codex-capture-test.png
could not create image from display

macOS 自体は画面全体、範囲、ウィンドウ単位のスクリーンショット取得機能を持っています。実画面を撮りたい場合は、OS 側のスクリーンショット機能や録画ツールを使うのが自然です。2 ただし、Codex の記事素材としては、ログをもとにしたターミナル風 GIF のほうが再現性を高くできます。

ログをフレームに分ける

GIF にする前に、コマンド実行ログをそのまま貼るのではなく、読者に見せたい状態ごとに分けます。今回なら 4 フレームで十分でした。

frame 1: ツール有無の確認
frame 2: 実画面キャプチャ失敗の確認
frame 3: PillowでGIFを生成
frame 4: GIFの形式とフレーム数を確認

ここで重要なのは、演出を増やしすぎないことです。環境構築記事で必要なのは、操作の雰囲気ではなく「どのコマンドを打ち、何が返ったか」です。フレームは少なめにし、1 フレームあたりの文字量も詰め込みすぎないほうが読みやすくなります。

GIF生成スクリプト

このリポジトリでは、検証用に scripts/generate-terminal-gif-demo.py を作成しました。中核は、Pillow の ImageDraw でターミナル風の画面を描き、最後に GIF として保存する部分です。

images[0].save(
OUT,
save_all=True,
append_images=images[1:],
duration=[1500, 1700, 1500, 1800],
loop=0,
optimize=True,
)

調整する主な項目は次の 4 つです。

項目意味調整例
FRAMES表示するコマンドとログ実際の記事で使うコマンドへ差し替える
WIDTH / HEIGHTGIFの解像度ブログ幅に合わせて 960x540 などにする
duration各フレームの表示時間長いログのフレームだけ長めにする
OUT出力先記事から参照しやすい画像ディレクトリにする

実行は次の形です。

$ python scripts/generate-terminal-gif-demo.py
sec/assets/img/codex-terminal-demo.gif
75402

生成後は、ファイル形式とフレーム数を確認します。

$ file sec/assets/img/codex-terminal-demo.gif
sec/assets/img/codex-terminal-demo.gif: GIF image data, version 89a, 960 x 540

$ python -c 'from PIL import Image; im=Image.open("sec/assets/img/codex-terminal-demo.gif"); print(im.format, im.size, getattr(im, "n_frames", 1))'
GIF (960, 540) 4

この確認まで記事作成手順に含めておくと、「GIF を作ったが壊れている」「1 枚目しか保存されていない」といったミスを避けやすくなります。

Docusaurus記事への埋め込み

このサイトでは、記事本文から相対パスで画像を参照しています。Docusaurus は Markdown の画像記法を処理でき、Markdown 内の画像参照をビルド時のアセットとして扱えます。3

今回の記事では、GIF を次の場所へ置きました。

sec/assets/img/codex-terminal-demo.gif

sec/notes/lab/codex-terminal-gif.md から見ると、画像参照は次のようになります。

![Codexのコマンド実行結果を反映したターミナル画面風GIF](../../assets/img/codex-terminal-demo.gif)

記事と画像の距離を短くしたい場合は、記事ファイルの近くに assets ディレクトリを置く方法もあります。ただし、このリポジトリでは既存記事が sec/assets/img を使っているため、既存の置き方に合わせました。

記事化するときの考え方

ターミナル画面風 GIF を「本物同等」として使うには、次の条件を守るのがよいです。

  • 実行していない成功ログを作らない
  • 失敗したコマンドは失敗として載せる
  • 長すぎるログは要点だけ抜き出し、全文は本文のコードブロックに分ける
  • GIF の見た目より、コマンドと出力の正確さを優先する
  • 生成スクリプトもリポジトリに残し、後から同じGIFを再生成できるようにする

今回の例では、screencapture が失敗したこともフレームに入れています。これは弱点ではなく、Codex 内でできることとできないことを読者に示す情報です。そのうえで、ログをもとに GIF を生成する流れを示せば、記事としての透明性も保てます。

まとめ

ローカル Codex で環境構築手順を検証し、その結果をブログ記事に載せる場合、実画面キャプチャにこだわる必要はありません。コマンドとログが実行結果に基づいていれば、ターミナル画面風 GIF は十分に説明力のある素材になります。

流れは単純です。

実行する
ログを整理する
フレームに分ける
PillowでGIFにする
Markdownに埋め込む

この方法なら、Codex の隔離環境で検証した結果をそのまま記事素材に変換できます。画面録画ツールが使えない場面でも、再現性のある手順記事を作れます。

参考資料(出典)

Footnotes

  1. Pillow, Image file formats - GIF Saving(公式ドキュメント)。GIF 保存時の save_allappend_imagesdurationloop の扱いを確認した。https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html

  2. Apple Support, Take a screenshot on Mac(公式サポート文書 / 2026年3月27日公開)。macOS の画面キャプチャ方法を確認した。https://support.apple.com/en-us/HT201361

  3. Docusaurus, Assets(公式ドキュメント)。Markdown 画像記法とアセット参照の扱いを確認した。https://docusaurus.io/docs/markdown-features/assets