空のキューと出力予定を確認して2状態を書き出す練習
2026年10月3日確認:最初はDRY_RUN = trueで出力予定だけを表示します。
所有の練習コピーでPracticeSwitchコンポにヌルCtrlを置き、チェックボックス制御のエフェクト名をToggleにします。
チェックはキー・式のない0/1にし、元の状態を記録してください。
1秒程度のPracticeRenderコンポに色付きソリッドを置き、不透明度へ下の式を設定します。
チェックOFFで0、ONで100になることを手動で確認してから書き出しへ進みます。
練習用のレンダリング項目で設定を確認し、レンダリング設定をPractice Render、MOVを出力する出力モジュール設定をPractice MOVという名前で保存します。
テンプレート保存に使った練習項目をキューから外し、既存の本番項目を含めず空のキューで試してください。
下のコードをrender-toggle.jsxとしてUTF-8で保存し、プロジェクトパネルでPracticeRenderだけを選択して実行します。
出力先には既存の空フォルダを選び、OFF.movとON.movの2つの予定、選択数、テンプレート名を確認します。
初期状態ではチェック変更・キュー追加・レンダリングを行いません。
所有の練習コピーで設定を確認した後、DRY_RUN = falseへ変更して実行する手順です。
OFFの処理完了を待ち、完了状態を確認してからONを開始します。
2つの状態を同時にキューへ積むと、共通チェックの値を最後の状態で評価するため、順番を分けます。
既存項目があるキュー、複数の同名制御、キーや式のあるチェック、空でないフォルダ、同名出力がある場合は開始しません。
テンプレート不在・途中停止・レンダリングエラーの場合は次の状態へ進まず、作ったキュー項目だけを外し、元のチェック値へ戻す処理を試みます。
復元自体が失敗した場合はその内容を表示するので、元の値と空キューを手動で照合してください。
出力ファイルには連番を付け、日本語などのコンポ名はファイル名部分をアンダースコアへ置き換えます。
テンプレートをMOV以外にした場合の拡張子変更や連番画像の出力には、この例をそのまま使わないでください。
書き出された映像や途中のファイルはCtrl+Zでは消えません。
OFF/ONの映像内容、ファイルの再生、元のチェック状態、キューを確認し、途中ファイルは確認用に残してください。
コードはJavaScriptの構文・模擬APIと保存したAPI資料で確認していますが、AE本体での適用・映像の一致・Undoの実行確認は未完了です。
| 入力・条件 | 操作・結果 | 確認する点 |
|---|---|---|
| DRY_RUN = true | 予定表示のみ | チェック・キューを変更しない |
| DRY_RUN = false | OFF完了後にON | 既存キューは拒否 |
| 途中失敗・復元 | 次の状態へ進まない | 元のチェックとキューを照合 |
仕様の照合には、コミュニティで保守されているRenderQueue API参照、RenderQueueItem API参照、OutputModule API参照を参照しました。
2026年10月3日:出力予定の確認、空キュー、OFF完了後のON実行、元のチェック状態への復元を含む例へ改修しました。
チェックボックス制御の切り替えに合わせて複数パターンをレンダリングする方法をまとめました。
スクリプトでチェック状態を切り替えながら、レンダリングキューの処理を自動化します。
例えば、チェックボックス制御で切り替えたいレイヤーの不透明度に、下記のエクスプレッションを設定します。
comp("PracticeSwitch").layer("Ctrl").effect("Toggle")(1) == 1 ? 100 : 0;
これでチェックボックスのオン・オフに応じて表示を切り替えられます。
手動で切り替えずに2パターンの書き出しを一括で実行するため、スクリプトを作成しました。
チェックボックスを切り替えて2通りレンダリングするスクリプト
(function () {
var DRY_RUN = true; // First check the plan. Set false only in your practice copy.
var RENDER_TEMPLATE = "Practice Render", OUTPUT_TEMPLATE = "Practice MOV";
var project = app.project;
if (!project) { alert("Open a practice project."); return; }
var queue = project.renderQueue, comps = [], files = [], created = [], i, j;
if (queue.rendering || queue.numItems !== 0) { alert("Use an empty, idle render queue."); return; }
if (!project.selection.length || project.selection.length > 5) { alert("Select 1 to 5 compositions in the Project panel."); return; }
for (i = 0; i < project.selection.length; i++) {
if (!(project.selection[i] instanceof CompItem)) { alert("Select compositions only."); return; }
comps.push(project.selection[i]);
}
var controlComp = null, controlLayer = null, effect = null, matches = 0;
for (i = 1; i <= project.numItems; i++) {
var item = project.item(i);
if (item instanceof CompItem && item.name === "PracticeSwitch") { controlComp = item; matches++; }
}
if (matches !== 1) { alert("Use exactly one PracticeSwitch comp."); return; }
matches = 0;
for (i = 1; i <= controlComp.numLayers; i++) {
if (controlComp.layer(i).name === "Ctrl") { controlLayer = controlComp.layer(i); matches++; }
}
if (matches !== 1 || controlLayer.locked) { alert("Use one unlocked Ctrl layer."); return; }
var effects = controlLayer.property("ADBE Effect Parade"); matches = 0;
if (effects) {
for (i = 1; i <= effects.numProperties; i++) {
if (effects.property(i).name === "Toggle") { effect = effects.property(i); matches++; }
}
}
if (matches !== 1 || effect.matchName !== "ADBE Checkbox Control") { alert("Use one Toggle Checkbox Control."); return; }
var checkbox = effect.property("ADBE Checkbox Control-0001");
if (!checkbox || checkbox.numKeys !== 0 || checkbox.expression !== "" || (checkbox.value !== 0 && checkbox.value !== 1)) {
alert("Use a static 0/1 checkbox without an expression."); return;
}
var folder = Folder.selectDialog("Choose an existing empty practice output folder");
if (!folder) { return; }
if (!folder.exists || folder.getFiles().length !== 0) { alert("Choose an empty folder."); return; }
var plan = [];
for (i = 0; i < comps.length; i++) {
var stem = (i + 1) + "_" + comps[i].name.replace(/[^A-Za-z0-9_-]/g, "_");
files[i] = [new File(folder.fsName + "/" + stem + "_OFF.mov"), new File(folder.fsName + "/" + stem + "_ON.mov")];
for (j = 0; j < 2; j++) {
if (files[i][j].exists) { alert("Output already exists."); return; }
plan.push(files[i][j].fsName);
}
}
if (DRY_RUN) {
alert("Plan only: no checkbox change, queue addition or render.\nTemplates: " + RENDER_TEMPLATE + " / " + OUTPUT_TEMPLATE + "\n" + plan.join("\n")); return;
}
if (queue.rendering || queue.numItems !== 0) { alert("Queue changed. Stop and review."); return; }
var original = checkbox.value, cleanupErrors = [], completed = 0;
function contains(values, target) {
for (var k = 0; k < values.length; k++) { if (values[k] === target) { return true; } }
return false;
}
function removeCreated() {
for (var k = created.length - 1; k >= 0; k--) {
try { created[k].remove(); } catch (error) { cleanupErrors.push(error.toString()); }
}
created = [];
}
try {
for (j = 0; j < 2; j++) {
checkbox.setValue(j);
for (i = 0; i < comps.length; i++) {
if (files[i][j].exists) { throw new Error("Output appeared; refusing overwrite."); }
var rq = queue.items.add(comps[i]); created.push(rq);
var om = rq.outputModule(1);
if (!contains(rq.templates, RENDER_TEMPLATE) || !contains(om.templates, OUTPUT_TEMPLATE)) {
throw new Error("Save the named render and MOV output templates first.");
}
rq.applyTemplate(RENDER_TEMPLATE); om.applyTemplate(OUTPUT_TEMPLATE);
om = rq.outputModule(1); om.file = files[i][j]; rq.render = true;
}
// render() returns after the queue finishes. Do not queue both states together.
queue.render();
for (i = 0; i < created.length; i++) {
if (created[i].status !== RQItemStatus.DONE) { throw new Error("Render stopped or failed; do not start the next state."); }
}
completed++; removeCreated();
if (cleanupErrors.length) { throw new Error("Queue cleanup failed; inspect the queue."); }
}
} catch (error) { alert("Stopped: " + error.toString() + "\nInspect and keep any partial practice output."); }
finally {
try { checkbox.setValue(original); } catch (error) { cleanupErrors.push("Checkbox restore: " + error.toString()); }
removeCreated();
if (cleanupErrors.length) { alert("Manual restoration needed:\n" + cleanupErrors.join("\n")); }
}
alert("Completed states: " + completed + " of 2. Check both files and the restored checkbox. Rendered files cannot be undone with Ctrl+Z.");
})();
参考:http://compojigoku.blog.fc2.com/blog-entry-18.html
After Effectsのほかの操作は、まとめからご覧いただけます。

旧実装の参考コードは、GitHubのMOTOKI-LLC/cg-method-codeにもまとめています。
レンダリングや書き出しを速くする方法は、ほかにもまとめています。




