HN 日本語サマリー

← 一覧へ戻る
Web開発

My video has unit tests

My video has unit tests (pertiller.tech)

15 pointsby Vieltrinker4 コメント

要約

この記事は、従来の動画編集ソフトを使わずに、JavaScriptとSVGを用いてプロモーションビデオをコードで生成するアプローチについて解説しています。コードベースで動画を管理することで、バージョン管理、テスト、ローカライズが容易になり、特に動画のシーケンスに対する単体テストが実装された点が注目されます。この手法により、動画の挙動をテスト可能なソフトウェアとして扱える可能性が示されています。

全文翻訳

コードで書かれた私の動画

AIエージェントから今日見た最も予想外の単体テストは、動画内のプッシュ通知が、アニメーション化されたチャートの価格が目標値に達する前に表示されないことをチェックするものでした。

動画の単体テスト。🤯

私のサイドプロジェクトである燃料価格アプリ「Petroly」の15秒間のプロモーションビデオが必要でした。Claude Codeは私のアプリのデザインを再利用するJavaScriptレンダラーを作成しました。その後、プレーンな言葉で変更を説明し、結果を見て改良することができました。

動画編集ソフトを開く必要はありませんでした。

チャート、通知、ソートアニメーション、トランジションはすべてソースコード内に存在します。それらを変更し、差分を確認して再度レンダリングできます。作業を進めるにつれて、タイミングのテスト、アプリからの翻訳、透明な角を持つ動画など、さらに多くの可能性が見えてきました。

コードで書かれた動画。

レンダラーを自分で実行する

完成した動画を見る前に、スライダーをドラッグしてみてください。

以下に表示されているのは動画ファイルではありません。ブラウザは動画を生成するのと同じレンダラーコアを実行しています。スライダーのすべての位置で、新しいSVGフレームが要求されます。言語を変更したり、シーンにジャンプしたり、SVGを開いてコードが生成したものを確認したりできます。

動画ファイルではありません

時間をドラッグして進める

ブラウザは、広告をレンダリングしたのと同じ frame(t) 関数を実行しています。スライダーのすべての位置で、新しいSVGが要求されます。

レンダラーをロード中…

フレームをロード中…25フレーム/秒

秒単位の時間

言語

このフレームのSVGを表示

プリレンダリングされた画像はありません。チャート、通知、ソートリスト、QRコードは、あなたが選択した正確な瞬間に計算されます。言語を選択すると、コピー、通貨、数値形式、QRコードの宛先がそれに合わせて変更されます。

動画は時間の関数である

その中心にあるアイデアは小さいです。

frame(timeInSeconds) // → その瞬間のSVG文字列

2秒で関数はオープニングを描画します。その後、価格チャートがターゲットをクロスし、通知が表示される様子を描画します。さらに後で、ステーションリストがソートされます。すべての位置、フェード、バウンスは t に対するちょっとした算術演算です。

それを動画に変換するために、レンダラーは15秒間、毎秒25フレームの375フレームを要求し、それらをFFmpegにストリームします。プロセスを writeToFfmpeg に短縮すると、ループは次のようになります。

for (let i = 0; i < DURATION * fps; i++) {
  const pixels = await sharp(Buffer.from(frame(i / fps)))
    .ensureAlpha()
    .raw()
    .toBuffer();
  await writeToFfmpeg(pixels);
}

時間 → SVG → RGBAピクセル → FFmpeg → 動画。 sharp は各SVGをピクセルに変換します。FFmpegはフレームをエンコードし、サウンドトラックを追加します。

通知が遅れて到着すべきなら、それはソースコード内の数値です。ある瞬間を検査したい場合は、その正確なフレームをレンダリングできます。同じ入力で、レンダラーは同じフレームシーケンスを生成します。

クリエイティブな部分は会話だった

最初のレンダリングで、私は反応するものがありました。そこから、プロセスは驚くほど馴染みのあるものに感じられました。結果を見て、変更すべきことを説明し、次のバージョンを確認します。

いくつかのリクエストは小さかったです。「ソートコントロールのタップをもう少し長く表示する」「少し左に移動する」「余分な境界線を削除する」。他のものはシーン全体の動作を変更しました。

選択肢を明確に示す。 ステーション比較は、一般的な最安値チャートよりも有用になりました。通りの名前はデモにはほとんど追加されず、読みにくかったです。行は現在、アプリ自身の価格カテゴリ(「非常に安い」から「非常に高い」まで)と色を使用しています。

動きに理由を与える。 表示されるタップは、ソートを距離から価格に変更します。他の行はフェードバックし、最も安いステーションが一番上に移動し、行が落ち着いた後にチェックマークが表示されます。何が起こったのか、そしてなぜ起こったのかを追うことができます。

各リクエストはコードの変更と新しいプレビューになりました。バージョンを並べて比較し、気に入った部分を保持できました。Gitはレンダラーとそのプレビューを一緒に保存できます。

エージェントが実装を担当しました。私はまだそれを見て判断する必要がありました。技術的に正しいバージョンでも、忙しすぎると感じられるものがいくつかありました。その部分は私の目と私の好みを必要としました。

私のエージェントが動画の単体テストを書いた

これが私を不意を突いた部分です。

価格アラートシーンでは、プッシュ通知はプロットされた価格がターゲットに達する前に表示されてはなりません。エージェントは、そのシーケンスをテストに変換しました。セットアップとインポートを省略すると、アイデアは数行に収まります。

test('the alert follows the price reaching its target', () => {
  const scene = SCENES.find((scene) => scene.kind === 'alert');
  const targetReachedAt = scene.from + ALERT_AT;

  const before = frame(targetReachedAt - 0.1);
  const after = frame(targetReachedAt + 0.1);

  assert.doesNotMatch(before, /id="push-notification"/);
  assert.match(after, /id="push-notification"/);
});

レンダラーは、プロットされた価格とチャートのアニメーションタイミングから ALERT_AT を計算します。シーンの開始を追加すると、ターゲットに到達した瞬間がわかります。その直前には通知がなく、直後には通知があります。自動テストは、編集ごとにこのシーケンスが引き続き機能することを確認します。微調整中にタイミングを確認するために、全体の動画を再生する必要さえありません。

他のテストでは、QRコードのレイアウトと余白、リストが距離でソートされて開始し、価格でソートされて終了すること、そして375個のSVGフレームのいずれにも NaN、Infinity、または undefined が含まれていないことを確認します。

最も安いステーションのハイライトが、すべての行が移動し終わるまで待つというチェックもあります。それはアサーションとして表現されたデザイン上の決定です。アプリの動作を保護するために使用するのと同じツールで、動画の動作も保護できます。

レンダリングされたピクセルにもチェックがあります。1つは、SVGに画像要素が存在することを確認するだけでなく、ロゴがラスタライズされていることを確認します。

プロモーションビデオを依頼したとき、これらのいずれかを依頼しようとは思わなかったでしょう。エージェントがそれをテスト可能なソフトウェアとして扱っているのを見るのは驚きでした。

テストはメカニクスを保護します。視聴は感覚を保護します。私は両方を望んでいます。

私のもう一つの発見:動画は透明にできる

PNGに透明なピクセルがあることは知っていました。動画もそうできるとは考えたこともありませんでした。

動画をiPhoneのディスプレイのように、角丸を含めて表示したかったのです。アルファチャンネルは、角の外側の領域を透明にし、動画を任意の背景にブレンドさせます。

このフレームの後ろの背景を変更してみてください。

レンダラーをロード中…

英語でユーロ価格でライブレンダリング。SVGの透明な角は背景を透過させ、CSSの角丸クリッピングなしで表示されます。「Phone frame」を選択すると、iPhoneスタイルのアウトラインの内側で見ることができます。

トリックは、その透明性をエクスポート全体で維持することです。編集マスターは、アルファチャンネル付きのMOVコンテナ内のProRes 4444です。.movというファイル名だけでは透明性は保証されません。コーデックとピクセル形式もそれをサポートする必要があります。

上記のフレームは、レンダラーによってライブ生成されたSVGです。以下のブラウザMP4には、下に合成された背景があります。それらのチェッカーボードは画像の一部です。編集マスターは実際のアルファチャンネルを保持します。

角丸の長方形はすでにSVG内の形状でした。周囲の透明なピクセルを維持することで、それを別のシーンの上に配置できる動画にしました。同じコードでそれができるとは知りませんでした。

12のローカライズ版、1つのアニメーション

ドイツ語版を気に入ったら、翻訳はレンダラーの別の入力になりました。12のバージョンは10言語をカバーしており、英語はユーロとポンド、ポルトガル語はヨーロッパ版とブラジル版があります。シーンとタイミングは共有されています。

  • ローカルフォーマット。 イギリス版は1リットルあたりのペンスとマイル単位の距離、デンマーク版はクローネ、ブラジル版はレアルを表示します。例示的な価格は順序を維持し、同じ瞬間にターゲットをクロスします。これらはライブ引用や通貨換算ではありません。
  • アプリ自身の言葉。 「Price alert」と5つの価格カテゴリは、アプリの翻訳から直接来ており、広告は広告対象のアプリと同じ言語で話します。
  • ローカライズされたリンク。 各バージョンは適切なQRコードの宛先を選択し、翻訳されたランディングページが利用できない場合は英語のページを使用します。コードはアニメーションで同じサイズと位置を維持します。
  • 収まるテキスト。 すべての文字列は実際のフォントで測定され、必要な場合にのみ縮小されます。「Très bon marché」は「Very cheap」よりもはるかに長いです。

翻訳にはまだ人間による確認が必要であり、レイアウトには視覚的なレビューが必要です。しかし、ソートアニメーションを改善すれば、次のレンダリング時にすべてのバージョンがその変更を継承できます。同期を維持する必要のある12個の個別のタイムラインはありません。

サウンドトラック付きのレンダリングされた動画はこちらです。言語を選択して再生してください。

[動画: Download the video]

結果、12のローカライズ版

同じコード。異なるオーディエンス。

15秒のPetroly広告。JavaScript、SVG、サウンドトラックからローカルでレンダリングされました。

動画の言語を選択

640 × 1,080 ピクセル
25フレーム/秒
375フレーム、1つのレンダラー

動画の説明を読む

Petrolyのロゴがより安い燃料を紹介します。ディーゼルチャートがターゲット価格まで下がり、価格アラート通知が表示されます。非常に安いから非常に高いまでの5つの色分けされたステーションカテゴリが、距離でソートされて開始します。タップすると、ソート順が価格に変更されます。最も安いステーションが一番上に移動し、チェックマークが表示されます。最後の画面には、アプリが無料であり、iPhoneとAndroidで利用可能であることが表示されます。QRコードは全体を通して固定されています。オーディオはインストゥルメンタル音楽のみです。

動画編集ソフト不要。編集ソフトウェアのサブスクリプション不要。

レンダリングスタックはJavaScript、SVG、sharp、FFmpegです。レンダリングツールはオープンソースです。サウンドトラックと効果音も無料ライセンスです。

私はすでにコーディングエージェントを使用してアプリを構築しており、エージェント型ソフトウェア開発に関する私の投稿で説明したとおりです。このプロジェクトは、コードで構築できるものの範囲を広げました。動画編集ソフトを購入したり、別のサブスクリプションを支払ったりする必要さえありませんでした。

これで、動画の変更を差分としてレビューし、通知が早すぎるかどうかをテストに尋ね、レイアウトを確認するために正確なフレームを1つレンダリングし、同じアニメーションから別の言語を生成できます。

見たいものを説明し、それが形になるのを見て、コードを通じて改善し続けることができます。動画がこのように機能することに、私はまだ興奮しています。