Amazonプライム感謝祭開催中!セール会場へ

After Effects│コンポ内のエクスプレッションをベイクするスクリプト

After Effectsのエクスプレッションは、評価結果をキーフレームへ変換(ベイク)できます。選んだプロパティだけを変換するなら標準機能を使います。この記事では、数値の式をコンポ全体の各フレームで処理するJSXも紹介し、1秒・30fpsの回転でキー数、値、Undoを検証します。

目次

標準機能でベイクする手順

  1. レイヤーを展開し、エクスプレッションが適用されているプロパティを選択します。
  2. メニューの「アニメーション」>「キーフレーム補助」>「エクスプレッションをキーフレームに変換」を実行します。複数のプロパティを同時に選択して変換することも可能です。

Adobeの公式説明「Convert an expression to keyframes」では、各フレームにキーを作り、元の式を残して無効にする動作が説明されています。以下の検証は、標準機能との比較ではなく掲載JSXの実行結果です。

掲載JSXを試すための準備と適用条件

  1. プロジェクトを別名保存し、1秒・30fpsの練習用コンポジションを作ります。検証では960×540に200×100のオレンジ色の平面を中央配置しました。
  2. 平面の回転を表示し、Altキーを押しながらストップウォッチをクリックして、式にtime * 10;を入力します。回転のキーフレームは0個にします。
  3. このコンポをアクティブにし、後掲コードをbake-numeric.jsxとしてUTF-8で保存します。
  4. 「ファイル」→「スクリプト」→「スクリプトファイルを実行」でJSXを開きます。
  5. レイヤーを選んでUキーを押し、回転のキーと0秒・0.5秒・最終フレームの値を確認します。

対象は、有効なエクスプレッションが付いた数値1つ、2D・3Dの数値配列、色の4要素配列です。コードはコンポ内の全レイヤーを調べます。選択プロパティだけ、ワークエリアだけを処理するものではありません。上限は3000フレーム・20プロパティ・合計20000サンプルです。

有効な式の付いたプロパティに既存キー・エラー・非対応の値型がある場合や、そのレイヤーがロックされている場合は、書き込み前に停止する設計です。文字列やシェイプパスを返す式は対象外ですが、文字やシェイプのレイヤーが存在するだけで停止するわけではありません。コードは式を持つプロパティの型を調べています。

1秒30fpsでの実機検証:30キー・値の差・Undo

2026年10月14日、Windows 11 Pro(10.0.26200)/After Effects 26.5(Build 89、日本語表示)で、掲載JSXを変更せず実行しました。回転のtime * 10;をベイクした結果は次のとおりです。

確認項目実機結果
キー数と範囲30個。最初は0秒、最後は29/30秒。1秒の終了境界にはキーなし
回転の値0秒=0度、0.5秒=5度、29/30秒=約9.666667度
全30フレームの数値比較元の式との差は最大約0.000000318度。厳密な数値一致ではない
0.5秒の描画比較前後に出力したPNGの全画素・全チャンネルが一致
式の状態文字列time * 10;を保持し、式は無効
Ctrl+Zを1回キー0個・式有効へ復帰。0.5秒は5度
回転に既存キー1個を追加して再実行Nothing changedの警告で停止。キー1個・式有効を維持
1秒30fpsの回転式を30個のキーへベイクし15フレームで5度と表示したAfter Effects画面
掲載JSXでtime * 10;をベイク。0〜29フレームに30キーが並び、15フレーム(0.5秒)の回転は5度。 2026年10月14日、Windows 11 Pro・AE 26.5(Build 89)で撮影。

今回の単純な回転では、各フレームの値の差はごく小さく、0.5秒の画像は一致しました。ただし、全フレームの画像、曲線的な式、位置の空間軌道、モーションブラーのサブフレーム評価まで一致したという結果ではありません。これらは未検証です。

スクリプトで一括ベイクするコード

全対象の値を先に読み取ってからキーを書き込む構成です。元の式の文字列は保持し、式を無効化して、キーの時間方向の補間をリニアに設定します。APIの補足にはコミュニティで保守されているProperty参照を利用できます。

(function () {
    var comp = app.project && app.project.activeItem;
    if (!(comp instanceof CompItem)) { alert("Open a composition."); return; }
    var targets = [], plans = [], times = [], frame = comp.frameDuration, i, j;
    function dimensions(type) {
        if (type === PropertyValueType.OneD) { return 1; }
        if (type === PropertyValueType.TwoD || type === PropertyValueType.TwoD_SPATIAL) { return 2; }
        if (type === PropertyValueType.ThreeD || type === PropertyValueType.ThreeD_SPATIAL) { return 3; }
        if (type === PropertyValueType.COLOR) { return 4; }
        return 0;
    }
    function collect(group, locked) {
        for (var k = 1; k <= group.numProperties; k++) {
            var prop = group.property(k);
            if (prop.propertyType !== PropertyType.PROPERTY) { collect(prop, locked); continue; }
            if (!prop.canSetExpression || !prop.expressionEnabled) { continue; }
            if (locked || prop.numKeys !== 0 || prop.expressionError || !dimensions(prop.propertyValueType)) {
                throw new Error("Only unlocked numeric expressions without existing keys are supported.");
            }
            targets.push(prop);
        }
    }
    try {
        if (!isFinite(frame) || frame <= 0 || !isFinite(comp.duration) || comp.duration <= 0) { throw new Error("Invalid duration."); }
        var count = Math.ceil(comp.duration / frame - 0.000001);
        if (count < 1 || count > 3000) { throw new Error("Use 1 to 3000 frames."); }
        for (i = 1; i <= comp.numLayers; i++) { collect(comp.layer(i), comp.layer(i).locked); }
        if (!targets.length || targets.length > 20 || targets.length * count > 20000) { throw new Error("Too many properties or samples, or no target."); }
        for (i = 0; i < count; i++) { times.push(i * frame); }
        // Sample every target before writing keys, including dependent expressions.
        for (i = 0; i < targets.length; i++) {
            var prop = targets[i], values = [], size = dimensions(prop.propertyValueType);
            for (j = 0; j < times.length; j++) {
                var value = prop.valueAtTime(times[j], false), copy;
                if (prop.expressionError) { throw new Error(prop.expressionError); }
                if (size === 1) {
                    if (typeof value !== "number" || !isFinite(value)) { throw new Error("Invalid scalar sample."); }
                    copy = value;
                } else {
                    if (!value || value.length !== size) { throw new Error("Invalid vector sample."); }
                    copy = [];
                    for (var n = 0; n < size; n++) {
                        if (typeof value[n] !== "number" || !isFinite(value[n])) { throw new Error("Invalid vector sample."); }
                        copy.push(value[n]);
                    }
                }
                values.push(copy);
            }
            plans.push({prop:prop, values:values});
        }
    } catch (error) { alert("Nothing changed: " + error.toString()); return; }
    app.beginUndoGroup("Bake numeric expressions at comp frames");
    try {
        for (i = 0; i < plans.length; i++) {
            var plan = plans[i]; plan.prop.setValuesAtTimes(times, plan.values);
            for (j = 1; j <= plan.prop.numKeys; j++) {
                plan.prop.setInterpolationTypeAtKey(j, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
            }
            plan.prop.expressionEnabled = false; // Keep the original expression text.
        }
    } catch (error) { alert("Stopped: " + error.toString() + "\nUndo or reopen your practice copy."); }
    finally { app.endUndoGroup(); }
})();

停止したとき・元の式に戻すとき

「Only unlocked numeric expressions without existing keys are supported.」と表示された場合は、有効な式が付くプロパティの既存キー、レイヤーロック、式のエラー、値型を確認します。今回の既存キー1個の試験では、追加のベイクキーを作らず停止しました。ほかの停止条件や複数プロパティ間の依存関係は、今回の実機試験には含めていません。

元の状態へ戻すには、実行直後にCtrl+Zを押して、キーが0個、式が有効、値が元どおりであることを確認します。式を有効にするだけではベイクしたキーが残ります。処理途中のエラーで一部だけ書き込まれた場合の復旧は未検証なので、保存した練習用コピーと比較してください。

コンポジションの長さを延ばす場合も再確認が必要です。このコードは実行時の最終フレームまでしかキーを作らず、式は無効のままです。処理時間の短縮効果は測定していません。

参考:25fpsで位置と回転をベイクした既存の画面

以下は2026年10月13日の別条件の画面です。25fpsのコンポジションで、位置にvalue + [Math.sin(time * 2 * Math.PI) * 180, 0]、回転にtime * 120を設定しています。6フレームの表示値は前後とも位置819.6, 360.0、回転28.8度です。今回検証した1秒・30fpsの例とは区別してください。この既存例のキー数は数えていません。

位置と回転の式を表示したベイク前のAfter Effects画面
2026-10-13撮影。Adobe After Effects 26.5.0 (Build 89)、Windows 11 Pro (10.0.26200)。実機画面、原寸保存。
コンポジション内の式をスクリプトでキーフレーム化したAfter Effectsの実行結果
2026-10-13撮影。Adobe After Effects 26.5.0 (Build 89)、Windows 11 Pro (10.0.26200)。実機画面、原寸保存。

After Effectsのほかの操作は、まとめからご覧いただけます。

旧実装の参考コードは、GitHubのMOTOKI-LLC/cg-method-codeにもまとめています。

エクスプレッションの書き方や、スクリプト化に関する記事は、ほかにもあります。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

After Effectsのおすすめ書籍

必要なPCスペック

周辺機器の優先度

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次