CopyButton

2026年5月27日水曜日

HyperFrames を Linux サーバーで動かした構築記録【GPU 不要・日本語フォント豆腐問題の解決まで】

Linux サーバーで動画をプログラマブルに生成したいエンジニア向けです。オープンソースの動画レンダリングエンジン HyperFrames を使い、HTML/CSS/GSAP で書いたアニメーションを headless Chrome + FFmpeg 経由で MP4 に変換する環境を、sudo 権限なし(一般ユーザー)の Ubuntu サーバーに構築した記録を全部書きます。最大の詰まりポイントだった日本語フォント豆腐問題(テキストが□□□になる)の解決策まで含めています。

この記事でできること

  • HTML/CSS/GSAP で書いたアニメーションを MP4 動画に自動変換できる
  • GPU なし・Docker なしで Linux サーバーに動画生成環境を構築できる
  • 日本語テキストが豆腐(□□□)になる問題の原因と解決方法がわかる

使ったもの

  • HyperFrames — HTML/CSS → MP4 変換エンジン(OSS、Apache 2.0)
  • nvm — Node.js バージョンマネージャー(sudo なしでインストール可)
  • Node.js 22 — HyperFrames の実行環境(22 以上が必須)
  • FFmpeg — 動画エンコーダー(静的バイナリで sudo なしインストール)
  • Python 3 — 呼び出し元ラッパースクリプト用

背景

HyperFrames を知ったきっかけは X(Twitter)のタイムラインでした。「GPU なし・Docker なしで HTML を動画に変換できる OSS」という投稿が英語圏のエンジニアを中心にかなり広まっていて、試してみようと思いました。

欲しかったのは SSH 経由で他のスクリプトから MP4 動画を自動生成する仕組みです。GPU を占有したくない、Docker を入れたくない、という縛りの中で HyperFrames は選択肢として合理的でした。HTML/CSS という既存の Web 技術でアニメーションを記述でき、CPU レンダリングで動き、一般ユーザー環境に収まる点が決め手でした。

環境: Ubuntu 22.04、sudo 権限なし(一般ユーザー)。

手順

1. Node.js 22+ のインストール(nvm 経由)

HyperFrames は Node.js 22 以上が必須です。多くの Ubuntu 環境では apt で入る Node.js が古いため、nvm でユーザーレベルにインストールします。

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
$ source ~/.bashrc
$ nvm install 22 && nvm alias default 22
$ node -v
v22.x.x

詰まりポイント: nvm でインストールした node~/.nvm/versions/node/v22.x.x/bin/ に置かれます。SSH 経由のスクリプト実行では ~/.bashrc が読み込まれないため PATH にこのパスが含まれません。SSH 経由で呼び出すスクリプトでは冒頭に以下を追加してください。

export NVM_DIR="$HOME/.nvm"
source "$NVM_DIR/nvm.sh"

2. FFmpeg のインストール(静的バイナリ)

sudo なしで FFmpeg を入れるため、静的ビルド済みバイナリを取得して ~/.local/bin/ に配置します。

$ mkdir -p ~/.local/bin
$ cd /tmp
$ curl -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz \
    | tar xJ
$ cp ffmpeg-*-static/ffmpeg ~/.local/bin/
$ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc
$ ffmpeg -version | head -1

3. HyperFrames のインストール

$ npm install -g hyperframes
$ hyperframes --version

4. Chrome Headless のインストール

HyperFrames はフレームのキャプチャに headless Chrome を使います。以下のコマンドで自動ダウンロードします。

$ hyperframes browser ensure

nodeffmpeg が PATH に通った状態で実行する必要があります。which node && which ffmpeg で両方の場所が表示されることを確認してから実行してください。

5. 日本語フォント問題の解決(最大の詰まりポイント)

HTML テンプレートに font-family: 'Noto Sans JP' を指定して動画を生成すると、日本語テキストが豆腐(□□□)になります。HyperFrames のログには「Fetched 1116 font face(s) for "Noto Sans JP" from Google Fonts」と出るのに、です。

原因

Google Fonts は Noto Sans JP を Unicode の範囲(サブセット)ごとに分割して配信します。HyperFrames がキャッシュしていたのは Latin サブセット(81KB)のみで、日本語グリフを含む CJK サブセット(1 ウェイトあたり 4〜5MB)はダウンロードされていませんでした。

headless Chrome はシステムフォントを直接参照するため、TTF をシステムフォントディレクトリに直接インストールするのが解決策です。

解決手順

以下のように curl で TTF を直接取得します。User-Agent をブラウザに偽装しないと woff2 サブセット版が返るため豆腐が解決しません。

$ mkdir -p ~/.local/share/fonts

# User-Agent をブラウザに偽装して TTF を取得(必須)
$ curl -L -A 'Mozilla/5.0 (X11; Linux x86_64)' \
    'https://fonts.gstatic.com/s/notosansjp/v56/-F6ofjtqLzI2JPCgQBnw7HFowAA.ttf' \
    -o ~/.local/share/fonts/NotoSansJP-Regular.ttf

# フォントキャッシュを更新
$ fc-cache -f ~/.local/share/fonts/

# 確認
$ fc-list | grep "Noto Sans JP"

fc-list の出力に NotoSansJP が表示されれば成功です。URL 中の版番号(v56)は変わる場合があります。最新の URL は Google Fonts の「Download family」から取得した zip を ~/.local/share/fonts/ に展開する方法でも対応できます(こちらの方が URL に依存しないため安定です)。

ビフォー・アフター

フォント修正前と修正後を並べました。

修正前 — 日本語テキストが□□□(豆腐)になっている
修正後 — 日本語テキストが正常に表示される

6. Python ラッパースクリプトの設計(オプション)

他のスクリプトから SSH 経由で呼び出す場合は、HyperFrames を薄くラップした Python スクリプトを用意すると便利です。設計のポイントは以下の 3 点です。

  • --prompt "テキスト" を受け取り、内部で HTML コンポジションを生成して HyperFrames に渡す(呼び出し元を HTML スキーマから隔離)
  • スタイル(fade / slide / motion)を引数で切り替え可能にする
  • fcntl.flock で同時実行を排他制御する(複数プロセスから呼ばれても安全)

呼び出し側は「SSH 1 コマンドで動画ファイルが返ってくる」インターフェースだけ知っていればよく、内部の HTML テンプレートが変わっても呼び出し側を修正する必要がありません。

完成システム

呼び出し元スクリプト(SSH)
▼ --prompt "テキスト" --output video.mp4
Python ラッパー(HTML 生成 + ロック)
HyperFrames(Node.js + Chrome + FFmpeg)
MP4 動画(720p / 30fps)

daemon なし、コマンド実行のみ。SSH 1 コマンドで動画ファイルが返ります。

よくある質問

Q. nvm: command not found になります

A. SSH 経由で実行すると ~/.bashrc が読み込まれないため発生します。スクリプト冒頭に source "$HOME/.nvm/nvm.sh" を追加してください。

Q. hyperframes browser ensure が失敗します

A. nodeffmpeg が PATH に通っているか確認してください。which node && which ffmpeg で両方の場所が表示されれば OK です。

Q. 日本語以外のフォント(中国語・韓国語など)も豆腐になります

A. 同様の原因です。対象フォントの完全版 TTF を ~/.local/share/fonts/ にインストールして fc-cache -f を実行してください。

Q. 動画が真っ黒になります

A. Chrome がフレームを描画する前にキャプチャされている場合があります。コンポジションの delay 設定を増やすか、CSS アニメーションの開始タイミングを見直してください。

Q. Node.js 20 でも動きますか?

A. HyperFrames は Node.js 22 以上が公式要件です。nvm install 22 && nvm use 22 で切り替えて使用してください。

※本記事の手順・コードは執筆時点(2026 年 5 月)で動作確認していますが、ライブラリやハードのバージョンが変わるとそのままでは動かない場合があります。動かない場合は コメント欄でお知らせください。

まとめ

HyperFrames を sudo なし Ubuntu サーバーに構築しました。詰まりポイントの本命は日本語フォント豆腐で、Google Fonts のサブセット配信仕様と headless Chrome のシステムフォント参照の組み合わせが原因でした。curl の User-Agent 偽装で TTF を取得してシステムフォントに置くことで解決できます。

この記事が役に立ったら X(Twitter)でシェアしてもらえると喜びます。

HyperFrames で作ったブログプロモーション動画

せっかくなので、このブログ「ON THE HAND」のプロモーション動画を HyperFrames で作りました。過去記事の画像+フェードトランジション+テキストキャプションを組み合わせた 30 秒の動画です。日本語テキストもフォント修正後は正常に表示されています。

ON THE HAND ブログのプロモーション動画(HyperFrames で生成・30 秒)

このブログを書いた人のアプリ

本ブログの著者が作った iOS 読書管理アプリ わたしのほんやさん を App Store で公開しています。本棚をシンプルに管理したい方はぜひ。

App Store で見る →

関連記事

参考

※この記事は Claude Code を使った自動更新を試しています。

0 件のコメント:

コメントを投稿