見出し画像

【Illustrator】スクリプトファイルの格納場所と実行方法

スクリプトに対する抵抗感がなくなってくると、「もっと活用していきたい!」という気持ちが湧いてきますよね。
ところが、さらにそれを進めようとすると、次の2つの壁にぶつかります。

  • スクリプトファイルをどこに置けばいいのか

  • どうやって実行すればいいのか

スクリプトの数が増えてくると、「どこに」「どうやって」管理するかが効率を左右します。この記事では、考えられる主な方法と、それぞれのメリット/デメリットを整理して紹介します。

ぜひ、ご自身のワークフローに合った最適な運用方法を見つけてみてください。


なお、最終的な結論は次のとおりです(異論はあると思います)。

  • スクリプトファイルは、Dropboxなどのクラウドに置く

  • Macユーザーであれば、Keyboard Maestroを使って実行する


1 | [その他のスクリプト]コマンドによる実行

[ファイル]メニューの[スクリプト]→[その他のスクリプト]を選ぶと、任意のスクリプトファイルを指定して実行できます。

この方法なら、スクリプトファイルをどこに置いていても動作します。
ただし、ファイルの場所や数が増えてくると、目的のスクリプトを探すのが手間になります(ソートもできませんし)。

そのため、この方法は「試しに動かしてみる」期間限定の使い方と割り切るのがよいでしょう。Illustratorの標準機能だけで実行できるので、まずは安心して試せます。

command(Ctrl)+ F12キーのキーボードショートカットも用意されています。


2 | [ファイル]メニューの[スクリプト]のサブメニューから実行する

スクリプトを常時使えるようにするには、Illustratorがインストールされているフォルダー内の「Presets」 → 「ja_JP」 → 「スクリプト」の中にスクリプトファイルを置きます。

Illustratorを再起動すると、[ファイル]メニューの[スクリプト]のサブメニューに、そのスクリプトが表示されるようになります。

また、サブフォルダーを作成しても認識されるので、用途ごとにフォルダーを分けて整理しておくと便利です。

この方法は、ブログや解説記事などでもよく紹介されています。
しかし、実際の運用では次の理由からあまりおすすめできません。

  • スクリプトを追加したら、Illustratorの再起動が必要

  • Illustratorのバージョンごとに同じ設定を繰り返す必要がある

  • アプリをアンインストールするとスクリプトも消えてしまう

  • そもそも「アプリケーション」フォルダー内はユーザーが手を入れるべき領域ではなく、セキュリティがどんどん強化されている

これらの点を踏まえると、長期的には別の場所にスクリプトを置く運用を検討したほうが安心です。

また、こちらに入れたスクリプトにはキーボードショートカットを設定することができません。

回避策

オススメするものではありませんが、次のような回避策があります。

  1. 「/Applications/Adobe Illustrator 2026/Presets.localized/ja_JP/スクリプト」の「スクリプト」フォルダーを削除

  2. 別途「スクリプト」(A)を作成し、JSXファイルを入れる

  3. Aのシンボリックリンクを「/Applications/Adobe Illustrator 2026/Presets.localized/ja_JP/」に戻す

  4. Illustratorを再起動

Illustratorは「スクリプト」フォルダーがあると(騙されて)認識しますが、実際にはAのフォルダーが参照されます。

  • AのフォルダーはDropboxなどのクラウドに置く

  • Aのフォルダー内にサブフォルダーを作ってもよい

  • 「/Applications/Adobe Illustrator 2026/Presets.localized/ja_JP/スクリプト」内にAを置いても認識しない


3 | サードパーティ製アプリ+スクリプトファイルはクラウドに保存

サードパーティ製のアプリを使うとIllustratorの標準機能では実現しづらい、柔軟なスクリプト管理やキーボードショートカットの設定が可能になります。

  • SPAi(Mac用)

  • Sppy(Windows用)

  • ScripshonTrees

  • Valet

SPAi(Mac用)

ものかのさんが開発されたMac用アプリ「SPAi」(スパイ)を使うと、専用パネルにスクリプトを登録してワンクリックで実行できます。
なんと無料で利用可能です。

  • スクリプトファイルがどこにあっても登録できる

  • キーボードショートカットを自由に割り当てられるのも大きな魅力です。Illustratorの標準設定では使えないcontrolキーを利用できるため、既存のショートカットを変更せずに新しい操作を追加できます。

hamkoさんとkinさんの紹介記事が非常にわかりやすいです。


Sppy(Windows用)

Windowsユーザー向けには、あるふぁ(仮)さんによる「Sppy for Ai」が同様の機能を提供しています。こちらも無料で使えるのが魅力です。

ScripshonTrees

ScripshonTreesは、純正エクステンションのため、Illustratorの標準パネルと同様に扱えます。

CCDA(Creative Cloudアプリケーション)で「ScripshonTrees」と検索します。

Valet

有料ですが、高速に実行できます。

Scripta!

やもさん謹製のスクリプトパレット。
Illustratorだけでなく、InDesign、Photoshopにも対応。決定版かも…

Scriptmeta

スクリプトはアップデートされても、利用者への通知やそれを調べる機能がありません。それを実現できます。


スクリプトファイルはDropboxなどのクラウドに置く

SPAi/Sppyでは、スクリプトファイルの保存場所に制限がありません。
そこで、Dropboxなどのクラウドストレージを格納場所にするのがおすすめ。

  • フォルダー階層を統一しておけば、異なるマシンでも同じ設定のまま運用できます。

  • どの環境からでも同じスクリプトを呼び出せるうえ、ファイルの更新や共有も自動で同期されるため、常に最新の状態を保てます。

  • どの環境からでも同じスクリプトを呼び出せるうえ、ファイルの更新や共有も自動で同期されるため、常に最新の状態を保てます。


4| Keyboard Maestro+MaestroPack

Macユーザーには、Keyboard Maestro を使ってスクリプトを実行する方法がおすすめです。

Keyboard Maestroは、キーボードショートカットや条件をトリガー(きっかけ)にして、アプリの操作を自動化できる高機能なマクロツールです。

Ai Execute Script File

Keyboard MaestroではIllustratorのスクリプトを直接実行できないため、したたか企画さんの「Ai Execute Script File」というプラグインを組み合わせて使います。

「Ai Execute Script File」は無料で使えますが、それを含む多数のプラグインがセットになったMaestroPackが販売されています。IllustratorやPhotoshopでKeyboard Maestroを使うには必需品と考えて、迷わず購入されることをオススメします。

たとえば、「/Users/takano/sw Dropbox/takano masahiro/ai-scripts/」に「Split Rows for Illustrator.jsx」を置いた場合には次のように設定します。

なぜ、Keyboard Maestroが必要なのか?

たとえば「コーナーウィジェットの表示/非表示」を切り替えるスクリプトは、次のように記述します。

app.executeMenuCommand('Live Corner Annotator');

このスクリプトは、現在の状態を判定して反対の状態に切り替えるだけのものです。表示なら非表示へ、非表示なら表示へ──いわゆる“トグル式”の動作しかできません。

Keyboard Maestroを使うと、Illustratorのメニュー操作を状態として指定できるため、次のような “状態の固定” が可能になります。

  • 「コーナーウィジェットを非表示にする」

  • 「必ずこの状態にしてからスクリプトを実行したい」

そのため、次の手順をKeyboard Maestroのアクションに挟み込むことで、
Illustratorが提供していない「状態指定」を実現できます。

  1. スクリプト実行前にコーナーウィジェットを非表示にする

  2. スクリプトを実行する

  3. 実行後に再びコーナーウィジェットを非表示に戻す

そこで、スクリプト実行前後に、Keyboard Maestroのアクションを入れることで、スクリプト実行前にコーナーウィジェットを非表示にし、スクリプト実行後にコーナーウィジェットを非表示にできます。

パレットを活用する

スクリプトが増えてくると、キーボードショートカットを覚える限界が来ます。また、ひとつひとつにキーボードショートカットを割り当てても、結局あまり使わないものが出てきます。

そこで、機能ごとにパレットにまとめて登録し、必要なときだけパレットからクリックして実行するという運用が便利です。

5 | そもそも登録が面倒…

「Keyboard Maestroどころか、SPAiの設定でさえちょっと腰が重い…」という方もいらっしゃると思います。

ランチャー

その場合は、ランチャー型のスクリプトも便利です。

  • スクリプトファイルを格納しているフォルダーを1回指定するだけで、そのフォルダー内のスクリプトを一覧表示し、選択して実行できます。

  • 一度フォルダーを選択すると、その情報を記憶しておき、次回起動時には自動的にそのフォルダーを読み込んでくれます。

コピーしてテキストエディタにペーストして保存。拡張子を.jsxに変更すればスクリプトファイルとして実行できます。

#target illustrator
#targetengine "ScriptLauncher"  // ★パレットを生かしておくための常駐エンジン名
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false);

/*
 Script Launcher (Palette) for Adobe Illustrator
 v1.3 — 2025-11-13 (Asia/Tokyo)

 JP:
  ・指定フォルダ以下の .jsx / .jsxbin / .js を走査し、サブフォルダ名をカテゴリとしてパレットに一覧表示。
  ・ダブルクリックまたは[Run]で実行。
  ・検索ボックスでフィルタ、カテゴリで絞り込み。
  ・前回選択したフォルダを記憶し、次回起動時に自動で読み込みます。
 EN:
  ・Scans a chosen folder for .jsx / .jsxbin / .js, treats first-level subfolders as categories,
    lists scripts in a palette, and runs them via $.evalFile().
  ・Includes search box and category filter.
  ・Remembers the last selected folder and restores it on next launch.
*/

(function () {
  // ---- Error guard ---------------------------------------------------------
  try {

    // ---- Utilities ---------------------------------------------------------
    function isMac() { return $.os.match(/Mac/i) !== null; }

    // ホームディレクトリを「~/」表記にする
    function prettifyPath(pathStr) {
      if (!pathStr) return pathStr;
      try {
        var home = Folder('~').fsName;
        if (pathStr.indexOf(home) === 0) {
          return "~" + pathStr.substring(home.length);
        }
      } catch (e) {}
      return pathStr;
    }

    // 設定保存用ファイル(このスクリプトと同じフォルダに作成)
    var PREFS_FILE = (function () {
      try {
        var thisFile = new File($.fileName);
        return new File(thisFile.parent.fsName + "/ScriptLauncherPrefs.txt");
      } catch (e) {
        return null;
      }
    })();

    // 最後に選択したフォルダを保存
    function saveLastFolder(folder) {
      if (!PREFS_FILE || !folder) return;
      try {
        PREFS_FILE.encoding = "UTF-8";
        if (!PREFS_FILE.open("w")) return;
        PREFS_FILE.write(folder.fsName);
        PREFS_FILE.close();
      } catch (e) {
        // ignore
      }
    }

    // 保存しておいたフォルダを読み込み
    function loadLastFolder() {
      if (!PREFS_FILE || !PREFS_FILE.exists) return null;
      try {
        PREFS_FILE.encoding = "UTF-8";
        if (!PREFS_FILE.open("r")) return null;
        var path = PREFS_FILE.read();
        PREFS_FILE.close();
        if (!path) return null;
        var f = new Folder(path);
        if (f.exists) return f;
      } catch (e) {
        // ignore
      }
      return null;
    }

    // 日本語を含むファイル名/フォルダ名が %E3%81… 形式で返ってくる場合の対策
    // 表示用の文字列だけ decodeURI し、実際の File オブジェクトには手を加えない
    function decodeForDisplay(str) {
      if (!str) return str;
      if (str.indexOf('%') === -1) return str;
      try {
        return decodeURI(str);
      } catch (e) {
        return str;
      }
    }

    function listScripts(root) {
      // Return [{name, file, category}] scanning one-level deep
      var results = [];
      if (!root || !root.exists) return results;

      // files directly under root as "(root)" category
      var rootFiles = root.getFiles(function (f) {
        return f instanceof File && /\.(jsxbin|jsx|js)$/i.test(f.name);
      });
      for (var i = 0; i < rootFiles.length; i++) {
        var dispRootName = rootFiles[i].displayName || rootFiles[i].name;
        dispRootName = decodeForDisplay(dispRootName);
        results.push({
          name: dispRootName,
          file: rootFiles[i],
          category: "(root)"
        });
      }

      // one-level subfolders as categories
      var subs = root.getFiles(function (f) { return f instanceof Folder; });
      for (var s = 0; s < subs.length; s++) {
        var catName = decodeForDisplay(subs[s].name);
        var files = subs[s].getFiles(function (f) {
          return f instanceof File && /\.(jsxbin|jsx|js)$/i.test(f.name);
        });
        for (var j = 0; j < files.length; j++) {
          var dispName = files[j].displayName || files[j].name;
          dispName = decodeForDisplay(dispName);
          results.push({
            name: dispName,
            file: files[j],
            category: catName
          });
        }
      }

      // sort by category > name
      results.sort(function (a, b) {
        if (a.category !== b.category) return (a.category > b.category) ? 1 : -1;
        return (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : -1;
      });
      return results;
    }

    function filterItems(items, keyword, category) {
      var kw = (keyword || "").toLowerCase();
      var cat = category || "すべて";
      var out = [];
      for (var i = 0; i < items.length; i++) {
        var okKw = !kw || (items[i].name.toLowerCase().indexOf(kw) !== -1);
        var okCat = (cat === "すべて") || (items[i].category === cat);
        if (okKw && okCat) out.push(items[i]);
      }
      return out;
    }

    function uniqueCategories(items) {
      var map = { "すべて": true };
      for (var i = 0; i < items.length; i++) map[items[i].category] = true;
      var keys = [];
      for (var k in map) if (map.hasOwnProperty(k)) keys.push(k);
      keys.sort(function (a, b) {
        if (a === "すべて") return -1;
        if (b === "すべて") return 1;
        return (a > b) ? 1 : -1;
      });
      return keys;
    }

    // ---- UI -----------------------------------------------------------------
    var dlg = new Window('palette', 'スクリプトランチャー v1.3');
    dlg.orientation = 'column';
    dlg.alignChildren = ['fill', 'top'];
    dlg.spacing = 8;
    dlg.margins = 12;

    // Row: folder + choose
    var rowFolder = dlg.add('group');
    rowFolder.orientation = 'row';
    rowFolder.alignChildren = ['left', 'center'];
    var stFolder = rowFolder.add('statictext', undefined, 'フォルダ未選択');
    stFolder.characters = 40;
    var btnChoose = rowFolder.add('button', undefined, 'フォルダ選択');

    // Row: search + category
    var rowFilter = dlg.add('group');
    rowFilter.orientation = 'row';
    rowFilter.alignChildren = ['fill', 'center'];
    var etSearch = rowFilter.add('edittext', undefined, '');
    etSearch.characters = 20;
    etSearch.helpTip = '検索(ファイル名を含む)';
    var ddCategory = rowFilter.add('dropdownlist', undefined, ['すべて']);
    ddCategory.selection = 0;

    // List
var lb = dlg.add('listbox', undefined, [], { multiselect: false });
lb.minimumSize.width = 420;
lb.minimumSize.height = 280;
// 高さが伸びすぎないように上限を設定(おおよそ20行分)
lb.maximumSize.height = 360;

    // Row: run + reveal
    var rowRun = dlg.add('group');
    rowRun.orientation = 'row';
    rowRun.alignChildren = ['fill', 'center'];
    var btnCancel = rowRun.add('button', undefined, 'キャンセル');
    btnCancel.onClick = function () { dlg.close(); };
    var btnReveal = rowRun.add(
      'button',
      undefined,
      isMac() ? 'Finder で表示' : 'エクスプローラーで表示'
    );
    // 右端に[実行]ボタンを寄せるためのスペーサー
    var runSpacer = rowRun.add('statictext', undefined, '');
    runSpacer.alignment = ['fill', 'center'];
    var btnRun = rowRun.add('button', undefined, '実行');

    // Data state
    var state = {
      root: null,
      allItems: [],
      shownItems: []
    };

    function refreshCategories() {
      var cats = uniqueCategories(state.allItems);
      ddCategory.removeAll();
      for (var i = 0; i < cats.length; i++) ddCategory.add('item', cats[i]);
      ddCategory.selection = 0;
    }

    function refreshList() {
      var kw = etSearch.text || '';
      var cat = ddCategory.selection ? ddCategory.selection.text : 'すべて';
      state.shownItems = filterItems(state.allItems, kw, cat);

      lb.removeAll();
      // group headers (category separators)
      var lastCat = null;
      for (var i = 0; i < state.shownItems.length; i++) {
        var it = state.shownItems[i];
        if (it.category !== lastCat) {
          var sep = lb.add('item', '— ' + it.category + ' —');
          sep.enabled = false; // visual separator
          lastCat = it.category;
        }
        var li = lb.add('item', '  ' + it.name);
        li._data = it;
      }
    }

    function chooseFolder() {
      var defaultFolder = state.root || loadLastFolder();
      var f;
      if (defaultFolder && defaultFolder.exists) {
        f = Folder.selectDialog(
          'スクリプトフォルダーを選択(.jsx / .jsxbin / .js)',
          defaultFolder
        );
      } else {
        f = Folder.selectDialog(
          'スクリプトフォルダーを選択(.jsx / .jsxbin / .js)'
        );
      }
      if (!f) return;
      state.root = f;
      stFolder.text = prettifyPath(f.fsName);
      state.allItems = listScripts(f);
      refreshCategories();
      refreshList();
      saveLastFolder(f);
    }

    function getSelectedItem() {
      if (!lb.selection || !lb.selection._data) return null;
      return lb.selection._data;
    }

    function runSelected() {
      var it = getSelectedItem();
      if (!it) return;

      // ランチャーから実行したら一度パレットを閉じる
      try {
        if (dlg && dlg.visible) {
          dlg.close();
        }
      } catch (e) {
        // ここでのエラーは無視
      }

      try {
        // BridgeTalk を使って Illustrator 本体に「そのスクリプトを単体実行してもらう」。
        // これにより、スクリプトメニューから実行したときとほぼ同じ環境で動作する。
        if (typeof BridgeTalk !== "undefined") {
          var bt = new BridgeTalk();
          bt.target = "illustrator";

          // ファイルパスを JS リテラル文字列にする
          var pathLiteral = uneval(it.file.fsName);

          bt.body =
            'var f = new File(' + pathLiteral + ');' +
            'if (f && f.exists) {' +
              '$.evalFile(f);' +
            '}';

          bt.send();
        } else {
          // BridgeTalk が使えない環境では、これまで通り同一エンジン内で実行
          $.evalFile(it.file);
        }
      } catch (e) {
        alert(
          "スクリプトの実行中にエラーが発生しました。\n\n" +
          "ファイル:\n" + it.file.fsName + "\n\n" +
          "エラー内容: " + e
        );
      }
    }

    function revealSelected() {
      var it = getSelectedItem();
      if (!it) return;
      try {
        it.file.parent.execute(); // open folder
      } catch (e) {
        // ignore
      }
    }

    // Events
    btnChoose.onClick = chooseFolder;
    etSearch.onChanging = function () { refreshList(); };
    ddCategory.onChange = function () { refreshList(); };
    btnRun.onClick = runSelected;
    btnReveal.onClick = revealSelected;
    lb.onDoubleClick = runSelected;

    // 前回選択したフォルダがあれば自動読み込み
    var initialFolder = loadLastFolder();
    if (initialFolder && initialFolder.exists) {
      state.root = initialFolder;
      stFolder.text = prettifyPath(initialFolder.fsName);
      state.allItems = listScripts(initialFolder);
      refreshCategories();
      refreshList();
    }

    // Show palette (non-modal)
    dlg.center();
    dlg.show();

  } catch (err) {
    // 万が一、構文エラーなどがあればここで捕まえる
    alert(
      'Script Launcher error:\n' +
      'Line: ' + (err.line || '?') + '\n' +
      err
    );
  }
})();

まとめ

スクリプトは「どこに置くか」「どう実行するか」で、使い勝手が大きく変わります。無理なくスクリプト活用を広げていきましょう!

  • まずは[その他のスクリプト]で“試し撃ち”

  • 気に入ったものは、SPAi/SppyやKeyboard Maestro、ScripshonTreesで常用環境へ

  • 複数マシンで使うなら、クラウド+共通フォルダー構造で管理

ダウンロード

ここから先は

0字 / 1ファイル

¥ 200

Amazon Payで支払うと最大2%還元のチャンス! 9/30まで

定期マガジンを購読されるとサンプルファイルをダウンロードいただけます。 https://note.com/dtp_tranist/m/mebd7eab21ea5