camera-3d-captions について
固定カメラのトーク映像に、奥行きのある3D字幕をフレーム単位で描画するHyperFrames用スキルです。通常の字幕ではなく、話者の前後や周囲を動く文字を作る映像編集者向けです。
主な機能
- 013Dカメラと文字のフレーム描画
- 02奥行きグループ、リング、フライスルー
- 03人物マットによる文字の遮蔽
- 04単語タイミングに合わせた字幕アニメーション
- 05任意の手描き文字スプライト
活用シーン
- 01固定カメラのトーク映像への立体字幕追加
- 02話者の周囲を巡る発話連動の文字アニメーション
- 03リング、階段、フライスルー形式の文字演出
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ heygen-com/ hyperframes-community-skills --skill camera-3d-captionsインストール後、Claude Code で/camera-3d-captionsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/kit/cam3d.jsfinish.jstables.jsreferences/recipes.mdworked-film.htmlscripts/font-metrics.pyframe-bounds.jsglyph-gaps.jsprep-take.shscripts/hand/build-sprites.pyhand-word.anim.js詳細
3Dカメラ字幕
After Effectsの演出(3Dカメラ、被写界深度、パス上のテキスト、Posterize Time 15、モーションブラー)を、HyperFrames向けの決定論的なフレーム単位のペインターとして再構築します。1つのクロックで背景プレート、マット、すべての文字を描画します。CSSアニメーションは使いません。
使う場面/使わない場面
- 使う場面: カメラが固定されたトーク映像(アバターまたは実写)、横長、ミディアムショット以上、1本あたり5~20秒。言葉が話者の周囲で奥行きのある動きをする必要があります。
- 使わない場面: 通常の字幕、カメラが動く映像や手持ち撮影(マットと背景プレートの変形は固定ショットを前提としています)、極端なクローズアップ(頭の後ろや周囲に空間がない)、人物マッティングモデルで被写体を分離できない映像。
要件と副作用(完全な一覧)
- ツール:
- Node 22+ およびテスト済みバージョンに固定した HyperFrames CLI、
npx [email protected](registry.npmjs.orgからダウンロードします)。以下のすべてのコマンドで、必ずこのバージョンを使ってください。 - PATH上の
ffmpeg。 fonttools、brotli、numpy、pillowをインストールしたPython 3。
- Node 22+ およびテスト済みバージョンに固定した HyperFrames CLI、
- マット:
npx [email protected] remove-backgroundはローカルで実行されます。初回実行時に、人物セグメンテーションモデル(約170 MB)を~/.cache/hyperframes/にダウンロードします。 - レンダー時間: コンポジションはプレビュー/レンダー時に
cdn.jsdelivr.netからGSAP 3.14.2を読み込みます。 - ワードクロック: ユーザーがすでにローカルで実行している、単語レベルの文字起こしツールを使います。開始タイミングの精度が重要です。通常のWhisperでは開始が遅れます。
- フォント: ユーザーが用意したファイルを使います。埋め込みがライセンスで許可されていることを確認してください。
- 手描きスタイル(任意):
p5-paint-animationスキルがインストールされ、セットアップ済みである必要があります(セットアップでは、固定バージョンのpuppeteer、Chrome for Testing、p5、p5.brushがダウンロードされます)。build-sprites.pyはヘッドレスで実行され、フレームはそのスキルのout/に書き込まれた後、削除されます。 - その他は不要: 認証情報不要、有料の呼び出しなし、アップロードなし。ファイルはプロジェクト内(
assets/、renders/)にのみ書き込まれます。
準備(テイクごとに1回)
- 区間と背景プレート。
bash scripts/prep-take.sh <take.mp4> <start_s> <dur_s> <project>/assetsを実行すると、次のファイルが生成されます。portion.mp4:音声ソース。plate-tall.mp4:左右にそれぞれ240 px、上に480 px、下に240 pxを反射パディングしたものです。これにより、素早いパン、トラック撮影、引きの動きでも端が見えません。person.webm:アルファマット。同じフレームを使用します。- スクリプトはその後、背景プレートとマットが区間映像と一致するか(サイズ、フレームレート、フレーム数)を確認し、不一致があれば失敗します。
- ワードクロック。 区間の開始からの秒数で、単語ごとのタイミングを用意します。
- フォント。 2~3種類の役割(キャプション/メイン/リング)を選び、続けて
python3 scripts/font-metrics.py assets/metrics.js key=font.woff2[@wght=…,opsz=…] …を実行します。- 可変フォントの場合は、ここで軸を指定し、CSSでも固定する必要があります(
font-variation-settings、font-optical-sizing: none)。そうしないと、ブラウザーがサイズに応じてopszを変え、単語が重なります。
- 可変フォントの場合は、ここで軸を指定し、CSSでも固定する必要があります(
- シルエット。 配置を始める前に、
person.webmのアルファから頭部のボックスと肩のラインを確認します。
ビルド
assets/kit/{cam3d.js,tables.js,finish.js}とmetrics.jsをプロジェクトのassets/にコピーします。references/worked-film.htmlは完全なリファレンス映像です。2つのショット、ボディワイプ、両方のリングタイプ、フライスルー、フィナーレ、カラーグレーディングが含まれます。メディアは含まれていません。references/recipes.mdには、奥行きを優先するグループ、ラップしたリング、階段状の配置、手描きの単語が記載されています。C3.init(metrics, {W, H}):- レンズはチュートリアルの垂直視野角(F = 1326.1·H/1080)を維持するため、
tables.jsは幅に応じたスケーリングなしで適用できます。 - フレーム幅が1440を超える場合は、
(W − 1440) / 2をwipe.xに加算します。
- レンズはチュートリアルの垂直視野角(F = 1326.1·H/1080)を維持するため、
ショット文法
4~6 個のビートを選びます。話された節は、それぞれ別のグループに分けます。
| ビート | 構成 | ルール |
|---|---|---|
| 素早く寄るパンチイン | camA のテーブル(502 px 低い位置から 19 f)に続いて linear でゆっくり寄る | プレート S0 は 1.1~1.3。フレームを静止させません |
| 奥行きグループ | 節ごとに D 1250 / 1500 / 2200 で 2~3 個のキャプショングループ | 手前ほど大きくし、影も大きくします。ゆっくり寄りながらトラックして視差を見せます |
| 背後のヒーロー | プレートと同じ奥行きの背後レイヤーにヒーローワードを置き、マストヘッド風に頭部を横切らせます | 頭部で中央の文字を隠します。60 % 以上は判読可能にし、アセンダーをフレーム内に収めます |
| 視差を使ったトラック | swing セグメント、tx 420 | 古いレイアウトを 3 ステップでフェードアウトし、視差で次のレイアウトを登場させます |
| ボディワイプ | 話者自身のマット、brightness(0) blur()、wipe.x から始まるエッジ | ショット A は帯の左側で、ショット B は右側でクリップします。両側で引き出します |
| 巻き付くリング | 話者の正面に置く水平な円(中心 Z 2000)、上方から 11~16°、回転 | 言葉が話されるのに合わせて、側面から小さく入り、正面を回って収まります。下側の弧は反転して正立表示にします |
| フライスルー | D 1500 / 2000 / 2500 にフレーズを配置し、カメラはその間をスイング | フォーカスをフレーズに追従させます |
| 階段状のフィナーレ | プッシュセグメント。キャプションの各単語を斜めに、奥へ行くほど小さく配置 | プッシュで手前の単語を引き離します |
ルール
- モーション:
- テキストは 15 fps にポスタライズします(テキスト自身のアニメーションと、それが映るカメラ)。プレートとマットは毎フレーム動きます。
- モーションブラーは 15 fps の半ステップにわたる 7 個のゴーストです。回転するリングでは
shutter: 0.5を使います。 - キャプションは音声より 0.2 s 先行し、15 fps のグリッドに合わせます:
fr(t) = 2·round((t − 0.2)·15)。 ENTRYに沿って登場させます:キャプションは 30 px、ヒーローは 110~260 px 上昇します。リングの単語は、パスに沿って最後の 30~44 px をイージングします。RING_ENTRYのオーバーシュートは、隣の単語がまだ配置されていない場合にのみ使います。
- 奥行き:
- 各グループに固有の D を設定します。プレートは 3000、キャプションは 1250~2400、巻き付くリングは約 1100~2700 です。
- 奥行きの影
[6, 16, 0.5, 1500]は 1500/(D − cz) でスケーリングします。 - 高さ 1080 px での DOF σ は 6.7·|D − focus|/D px です。フラットなキャプションは最大 1.2 px に制限し、リングのグリフにはぼかしをすべて適用します。
- サイズ:
size/riseは、着地時のカメラ(tland)での画面上の px です。スプライトは画面上のサイズでレンダリングします。 - スペーシング:
- リングのテキストは必ず
ringLineを通します(画面上の字送り。タイプ組みは track 1.10、gap 26~30、手描きは track 1.0、 gap 28)。 - 回転するリングは、ポーズごとに再レイアウトします。
- リングのテキストは必ず
- オクルージョン:
- リングは話者の手前に描画します。
- 単語を背後/手前のインスタンスに分割(
side、zSplit)するのは、頭部の後ろを通過させる場合のみです。
- 判読性:
- キャプションはフレームの暗い側に配置します。
- 肌や明るい服の上を横切るテキストには、暗いハローを付けます。
- 画面上では、末尾にピリオドを付けません。
- グレード(任意):
finish.jsはカーブ、肌向けの彩度 1.12、フレームごとに再生成されるグレインを適用します。不透明なシーン(プレート+背後のテキスト+マット)は、フィルターを適用したラッパーに入れます。手前のテキストにも同じグレードを適用し、グレインは上から合成します。これにより、背後/手前に分割された単語も同じ色になります(references/worked-film.htmlを参照)。
スタイル
- エディトリアル: コンデンス体のディスプレイセリフを使い、ヒーローはイタリックにします。キャプションにはテキスト用のセリフ体を使い、クリーム色にアクセントカラーを 1 色加えます。
- ボールド: ヒーローには太いグロテスク体、キャプションにはライトウェイトの書体を使い、彩度の高いアクセントカラーを 1 色加えます(制作例の映像)。
- 手描き:
scripts/hand/build-sprites.pyの p5.brush による描画スプライトを使います:- 各単語は表示開始時点から自ら描画されます。
- リングでは単語全体を接線に合わせて回転し、奥行きに応じてスケーリングして、より大きく平たいリング上に配置します。
- レシピは
references/recipes.mdにあります。
検証
npx [email protected] check . --no-contrast。ゴーストレイヤーが WCAG のコントラストチェックに引っかかります。ワイプとワイプの境目が重なるのは意図した動作です。- プレビュー画面で
scripts/frame-bounds.jsを貼り付け、__frameBounds(0, dur)を実行します。[]を返す必要があります。表示中、5 ステップ以上にわたってフレーム外にあるグループがないことを確認します。
scripts/glyph-gaps.jsを貼り付け、静止時に__glyphGaps(t)を実行します。- 単語をまたいだ接触がないこと。
- 平らな単語は 1 つのボックスとして計測されます(ディセンダーによる誤検出は許容します)。イタリック体の f の張り出しは負の値になります。ワイプ帯の反対側にある単語も両方表示されます。
- 単語間の間隔:レンダリングされた単語間の隙間は、スペース 1 文字分の送り幅とほぼ同じです。
- 各ビートのスナップショットを撮り、
npx [email protected] render . --crf 12でレンダリングし、ビートごとにフル解像度のフレームを確認します。
制限事項
- マットの境界は細い髪の毛でちらつきます。ワイプ中にミラーリングされたパッドが一瞬表示されます。
- 話者がフレームいっぱいに映ると背後のスペースがほとんどなくなります。マストヘッドの高さにするか、肩の後ろに隠してください。
snapshot --atは同じページを共有するため、キャプチャーごとに粒子のパターンは変わりません。粒子の状態はレンダリング結果で判断してください。- グレーディングと多数のゴーストレイヤーを使ったレンダリングには、通常のレンダリングの約 2 倍の時間がかかります。
コメント
Markdown 対応