UXP スクリプト (.psjs) で Photoshop を駆動する
エージェント向け実行可能レシピ: Photoshopでのドキュメント作成、編集、エクスポート。事実は2種類に分類されます:
- 公式: Adobe UXP ドキュメントからの情報。末尾にリンクあり。
- 実測: Windows および macOS、Adobe Photoshop 2026 で
.psjsを実行して確認した経験。未確認のものは 未確認 とマークされており、公式APIとして扱わないでください。
成功基準: スクリプトは結果JSONを書き出す(done / ok / fatal / errs を含む)。タスクで指定されたターゲットドキュメントのみを変更し、他の開かれているドキュメントには影響を与えない。ピクセル単位の位置合わせが必要な場合は、PNGをエクスポートし、ゴールデンイメージとΔE / ピクセル差を比較してからイテレーションする。
まず立ち止まる: タスクでどのドキュメントを変更するかが指定されていない場合、またはユーザーが未保存の変更があるドキュメントを上書き保存しようとしており、タスクでそれが明示的に許可されていない場合。
1. 使用する/しない場合
.psjs を使用する場合:
- Photoshopが必要な処理: レイヤースタイル付きピクセルのレンダリング、レイヤーごとのスライスエクスポート、batchPlayを使用した形状/テキスト/エフェクトの作成、結果のPSD/PNGへの保存。
- PSD/PSBからスライスリストを推測し、レビュー後に1x PNGとエンジン非依存のレイアウトJSONをエクスポートする場合(第9節参照)。
- エージェントがタスクを一度に実行する場合(スクリプト作成 → 起動 → ログのポーリング → 成果物のコピー)、永続的なパネルは不要。
Photoshopを起動しない場合:
- 読み取り専用のレイヤーツリー、名前、ID、テキスト、おおよそのバウンズのみが必要な場合:
psd-toolsまたはag-psdでオフライン解析で十分。実測:psd-toolsのlayer_idは UXPlayer.idと一致するため、オフライン構造で位置を特定し、レンダリング/エクスポートのみをPSに任せることができる。ただし、psd-tools の bbox は レイヤーエフェクトを含まない ため、最終的な視覚的なバウンズはPS内で計算する必要がある。
UXP プラグインを使用する場合:
- 永続的な双方向チャネルが必要な場合(例: MCP ブリッジ、パネル、WebSocket)。公式: スクリプトには マニフェスト / パネルがありません。Network、LaunchProcess、WebView、IPC はすべて利用できません。これらの機能はプラグインとして作成し、マニフェストで権限を宣言する必要があります。
- 公式: プラグインから別の
.psjsを呼び出すことはできません。ただし、スクリプト内のUXPコードは一般的にプラグイン内で実行可能です。
ExtendScript / JSX を使用する場合:
- ターゲットが Photoshop 23.5 より前の場合、または Windows COM
DoJavaScript/ macOS AppleScriptdo javascript/ CEPevalScriptしか使用できない場合。JSX は ES3、同期 API、メンテナンスモードです。psx.jsx(xbytor の ExtendScript ヘルパーライブラリ)をランタイムとして扱わないでください。
2. 公式の要点(最初に覚える)
- スタンドアロンUXPスクリプトは Photoshop 23.5 以降で使用可能で、拡張子は
.psjsです。デバッグには UXP Developer Tool ≥ 1.6 を使用できますが、スクリプトの実行にUDTは必要ありません。 - 公式の起動方法:
File > Scripts > Browse...;.psjsを Dock アイコン(Mac)または Photoshop ウィンドウの開かれているドキュメントエリア外(Mac / Win)にドラッグ&ドロップ; アクションでスクリプトを再生。ダブルクリックでの実行は以前「近日公開」とされていました。 - スクリプトはモダンJSであり、トップレベル
awaitをサポートします。公式サンプルと実測の両方がこれに依存しています。「async mainを定義したのに誰もawait main()しない」というコードを書かないでください。すぐに終了してしまいます。 - ドキュメントまたはアプリケーションの状態を変更する操作は、
require("photoshop").core.executeAsModal(fn, { commandName })内にラップする必要があります。commandNameはプログレスバーに表示されます(スクリプトが約2〜3秒以上かかる場合にプログレスバーが表示され、ユーザーはキャンセル可能)。 - DOMが不十分な場合は、
require("photoshop").action.batchPlay(descriptors, options)を使用します。デスクリプタは actionJSON です。公式ではDOMを優先することを推奨しています。「開発者モード」の Actions パネルにある Copy As JavaScript、またはPlugins > Development > Record Action Commands...を使用してデスクリプタを記録し、キー名をでっち上げないでください。 dialogOptionsは各デスクリプタの_optionsに記述し、値は"silent"(デフォルト、エラー時もダイアログ表示なし)、"dontDisplay"(通常は表示しないが、パラメータ不足やエラー時に表示される可能性あり)、"display"から選択します。実測(PS 2026): エージェントは"silent"を使用する必要があります。"dontDisplay"はコマンド失敗時にブロッキングエラーボックスを表示することがあります(例:命令「取得」は現在利用できません。)。スクリプトは誰かが「OK」をクリックするまで待機し続けます。クリック後、{_obj:"error", message:"", result:-128}が返ります(-128 は公式のユーザーキャンセルコード)。"silent"はダイアログを表示せず、約 1~5ms で{_obj:"error", message:"スクリプト名: 命令「…」は現在利用できません。", result:-25920}を返します。以前は{ dialogOptions: "dontDisplay" }をbatchPlayの第二引数として渡してもエラーになりませんでしたが、公式オプションテーブルにはこのキーはなく、"display"を使用してそれが有効かどうかを安全に検証することもできません。新しいコードではdialogOptionsをデスクリプタの_optionsに記述し、値は"silent"を使用してください。batchPlayのパラメータが不正な場合は reject されます。ターゲットが存在しないなどの実行時エラーは resolve され、{_obj:"error", message, result}を返します。result === -128はユーザーキャンセルを示します。必ず返り値の配列をチェックしてください。- ファイルシステム: スクリプトにはマニフェストがなく、権限はPhotoshopによって組み込まれています。公式のスクリプトセクションには、ファイル選択子と
getTemporaryFolder()が使用可能と記載されています。getEntryWithUrl/createSessionTokenは公式の FileSystemProvider API です(第4節の実測を参照)。 require("uxp").scriptはexecutionContext、args、setResult(result)を提供します。公式FAQ(初回リリース時の説明)には、最初のバージョンではスクリプトへのパラメータ渡しをサポートしていないと記載されていました。コマンドライン引数やscript.argsにタスク設定を渡すことに依存しないでください。パスとパラメータはスクリプトに直接記述するか、隣接するJSONファイルを読み込ませてください。 実測(Windows / PS 2026、Photoshop.exe script.psjs):script.argsは[]です。スクリプトパスの後に追加のCLI引数を指定すると、スクリプトは実行されません(3分以内に結果ファイルは作成されず)、ランチャーはすぐに戻り、終了コード0で、stdoutにスクリプト出力はありません。余分なCLI引数は渡さないでください。setResultは呼び出し可能でundefinedを返しますが、Photoshop.exeの終了コードや stdout には現れません。常に結果ファイルを使用してください。- 同時に実行できるスクリプトは1つのみで、スクリプトから別のスクリプトを呼び出すことはできません。
- 公式
executionContext:isCancelled/onCancelはユーザーキャンセルに応答するために使用します。reportProgress({ value, commandName })はプログレスバーを更新します。hostControl.suspendHistory({ documentID, name })+resumeHistory(id, commit)は一連の変更を1つの履歴ステップに結合し、アーティストが一度の元に戻すで元に戻せるようにします。 実測:isCancelledは boolean。reportProgressは呼び出し可能でundefinedを返します。suspendHistory({documentID, name})は{historySuspensionID}を返し、resumeHistory(id)はその後の複数の変更を1つのステップに結合し、その名前がdoc.historyStatesに表示されます。hostControlの列挙可能なキーは空の場合があるため、Object.getOwnPropertyNamesを使用してください。履歴の読み取りにはDOM(doc.historyStates/doc.activeHistoryState)を使用し、batchPlaygethistoryStatesCountは使用しないでください(そのコマンドは利用できません。第7節参照)。
3. エージェントの起動とポーリング(Windowsで実測済み)
公式には、「コマンドラインから .psjs を Photoshop.exe に渡す」ことは正式なインターフェースとして文書化されていません。実測(Windows / Photoshop 2026):
& "C:\Program Files\Adobe\Adobe Photoshop 2026\Photoshop.exe" "D:\work\ps-job\run_job.psjs"
- Creative Cloud デスクトップアプリ、UDT、または開発者モードは必要ありません。
- Photoshop が既に開かれている場合、スクリプトは既存のインスタンスで実行されます。
- ランチャーはすぐに戻ります。スクリプトはPS内で非同期的に実行され続けます。スクリプト自身が書き出す結果JSON(
done、ok、fatal、errsを含めることを推奨)をポーリングする必要があり、プロセスの終了コードで成功/失敗を判断しないでください。 - テストでは、エクスポートスクリプトが
.psbを28枚のスライスにエクスポートするのに約18秒かかりました(ファイルを開くのに約10秒を含む)、そしてexport_log.jsonを書き出しました。 - 実測(Windows / PS 2026): ファイル関連付けが存在します(
.psjs=Photoshop.PSJSFileType.200、ftype はPhotoshop.exe "%1")。Start-Process script.psjsは実際にスクリプトを実行し、結果ファイルを書き出します。エージェントは依然として明示的にPhotoshop.exe+ スクリプトパスを指定し、結果ファイルを基準とすることを推奨します。 - 起動前に、PSがモーダルダイアログを表示していないことを確認してください(クラッシュ後の「ドキュメントを復元」プロンプト、保存ダイアログなど)。ダイアログがある場合、スクリプトは期待通りに実行されず、ポーリングはタイムアウトします。タイムアウトした場合は、まずスクリーンショットを撮ってPSのインターフェースを確認し、盲目的に再実行しないでください。
リモートエージェントフロー: エージェント側で .psjs を作成 → Photoshopがインストールされたマシンにコピー(ユーザーが許可したディレクトリのみ)→ シェルで起動しログをポーリング → PNG/PSD/ログをコピー → 必要に応じてピクセル比較を実行。
ポーリングの例(PowerShell):
$ps = "C:\Program Files\Adobe\Adobe Photoshop 2026\Photoshop.exe"
$script = "D:\work\ps-job\run_job.psjs"
$log = "D:\work\ps-job\job_log.json"
if (Test-Path $log) { Remove-Item $log }
& $ps $script
$deadline = (Get-Date).AddMinutes(10)
do {
Start-Sleep -Seconds 2
if (Test-Path $log) {
$j = Get-Content $log -Raw | ConvertFrom-Json
if ($j.done) {
$j | ConvertTo-Json -Depth 8
if (-not $j.ok) { exit 1 }
break
}
}
if ((Get-Date) -gt $deadline) { throw "timeout waiting for $log" }
} while ($true)
macOS(実測、Photoshop 2026、Mac mini): 公式にはDock/ウィンドウへのドラッグのみが記載されています。以下のコマンドライン起動は公式ドキュメントには見つかりませんでしたが、使用可能であることが確認されています:
open -a "Adobe Photoshop 2026" /path/to/run_job.psjs
# .psjs が関連付けられている場合: open /path/to/run_job.psjs
- コールドスタート: PS が起動していない場合、
open -aは約 0.3 秒で戻り(exit 0)、PSの起動後にスクリプトが自動実行され、約 8 秒で結果ファイルを書き出します。 - ホットスタート: PS が既に実行されている場合、スクリプトは既存のインスタンスで実行され、数秒で結果を書き出します。
-aなしで、ファイル関連付けを介したopen xxx.psjsも同様に実行されます。getEntryWithUrl("file:/Users/<user>/...")で、選択子なしでファイルに書き込めます。- Windows と同様: ランチャーはすぐに戻るため、結果ファイルをポーリングする必要があります。余分なコマンドライン引数を追加しないでください。
ポーリングの例(zsh):
log=~/ps-job/job_log.json; rm -f "$log"
open -a "Adobe Photoshop 2026" ~/ps-job/run_job.psjs
for i in {1..300}; do [ -f "$log" ] && grep -Eq '"done": ?true' "$log" && break; sleep 2; done
cat "$log"
スケルトンスクリプトは examples/run_job.psjs を参照(トップレベル await、executeAsModal、ドキュメントIDガード、結果ファイル、try/catch)。実測: このスケルトンに従って実行成功:done/ok の書き出し、preview.png のエクスポート、自分で作成したドキュメントのクローズ、他の開かれているドキュメントのIDセットは変更されない。
4. ファイルアクセス
公式 FileSystemProvider: getFileForOpening / getFileForSaving / getFolder、getTemporaryFolder、getEntryWithUrl(url)、createEntryWithUrl、createSessionToken(entry)。
batchPlay に渡す _path は セッショントークン である必要があり、裸のシステムパスではいけません。公式説明: Photoshop DOM を介する場合(例: app.open(file)、doc.saveAs.psd(file, …))、File/Folder エントリを直接渡すことができ、ホストが自動的にトークンに変換します。
実測(PS 2026 スクリプト、選択子を表示せず):
const fs = require("uxp").storage.localFileSystem;
const root = await fs.getEntryWithUrl("file:/D:/work/ps-job"); // ディレクトリは既に存在する必要があります
const out = await root.createFile("job_log.json", { overwrite: true });
await out.write(JSON.stringify(log, null, 2));
file:/D:/... のようなURLはWindowsで使用可能です。スクリプトセクションでは依然として選択子 + 一時ディレクトリのみが保証されています。「任意のパス、選択子なし」は PS 2026 での実測動作として扱い、バージョンを変更する場合はまず書き込みのスモークテストを行ってください。ネットワークモジュールは呼び出さないでください。公式スクリプト環境では禁止されています。
5. ドキュメントの範囲と安全性(必須)
原則: スクリプトはタスクで指定されたターゲットドキュメントのみを操作します。ターゲットはスクリプトが新規作成したドキュメント、またはタスクで指定された既存のPSD(既存のデザイン案を反復する一般的なシナリオ)のいずれかです。他の開かれているドキュメントは一切変更、保存、クローズしません。
ターゲットセット targets の決定:
- 新規作成:
app.createDocument()が返すIDをtargetsに追加します。 - 既存のPSDの反復: タスクで指定されたパスを使用して特定します。まず
app.documents内でdoc.pathによって既に開かれているかどうかを確認します。開かれていればそのインスタンスを直接使用します(2番目のコピーは開かない)。開かれていない場合はapp.open(entry)を実行します。名前のみの一致は信頼できません(同名、「- 復元済み」のコピーなど)。パスを優先し、次にタスクで指定されたドキュメントIDを使用します。実測: パスで同じインスタンスを再利用できます(同じドキュメントID、2番目のコピーは開かれません)。未保存の編集後、doc.saved === falseになります。saveAs(..., true)で新しいバージョンとして保存した場合、元のファイルのmtimeとサイズは変更されず、ドキュメントは開かれたまま、元のパスを指し続けます。Windows ではdoc.pathはD:\\work\\file.psdのようになります。復元されたドキュメント(例: 「xxx-復元済み」)はpathが空でsaved === falseである可能性があり、パスでは見つからないため、タスクで指定されたドキュメントIDを使用する必要があります。 - 一時ドキュメント(例: 「レイヤーから新規」のスライス)は
targetsに追加し、使用後にcloseWithoutSaving()します。
ガード: すべての batchPlay、保存、クローズの前に、app.activeDocument.id が targets 内にあるかどうかを確認します。このチェックは「暗黙的に現在のドキュメントを指す」デスクリプタのみを対象とします。デスクリプタ内で明示的に { _ref: "document", _id } と記述されている場合、そのIDもチェックする必要があります。実行前と実行後にそれぞれ app.documents.map(d => ({ name: d.name, id: d.id, path: d.path })) をログに記録します。
実測: make レイヤー時に非アクティブドキュメントの { _ref: "document", _id } を指定すると、そのドキュメントにレイヤーが作成され、activeDocument は変更されません。したがって、明示的なIDもチェックする必要があります。ただし、set は非アクティブドキュメントに対しては使用できません(第7節参照)。プロパティを変更するには、まず app.activeDocument = target を実行してから set を実行します。
既存のドキュメントを変更する場合:
- ターゲットドキュメントが既に開かれており、未保存の変更がある(公式
doc.saved === false)場合、ユーザーが手動で編集していることを意味します。デフォルトでは、その上で編集を続行できます(これはまさに反復タスクです)。ただし、上書き保存はしないでください。タスクで明示的に要求されている場合を除きます。まずログに、実行前にダーティ状態であったことを記録してください。 hostControl.suspendHistoryを使用して、今回のスクリプトによる変更を1つの履歴ステップに結合し、ユーザーが一度のCtrl+Zで元に戻せるようにします。- 保存戦略はタスクに従います。デフォルトでは新しいバージョンとして保存します(例:
xxx_v14.psd)。元のファイルは保持します。タスクで「その場で更新」が明示的に要求されている場合のみdoc.save()を実行します。 - スクリプト終了時、ユーザーが元々開いていたターゲットドキュメントはクローズしないでください。クローズするのは、スクリプト自身が開いたり作成したりしたドキュメントのうち、タスクで保持を要求されていないもののみです。
自動クリーンアップ: 公式 executionContext.hostControl.registerAutoCloseDocument(docID) は、ユーザーがキャンセルした場合やモーダルが終了した場合に一時ドキュメントを自動的にクローズします。これはスクリプトが新規作成したドキュメントにのみ使用します。アーティストが編集を継続するために残す場合は、先に unregisterAutoCloseDocument を実行します。ユーザーが既に持っているドキュメントに自動クローズを登録しないでください。
6. 検証サイクル
- スクリプトでPNGをエクスポートします(必要に応じてPSDも保存)。
- エージェント側でゴールデンイメージと比較します(CIEDE2000 ΔE、ピクセル差、部分拡大)。
- 差異に基づいてスクリプトを変更します(パス、グラデーション、レイヤースタイル)。ユーザーが開いているドキュメントを手動で編集して、その再現性を期待しないでください。
- 再実行、再エクスポート、再比較を行い、基準に達するか、残りの差異を説明できるまで繰り返します。
7. 実測の落とし穴
-
dialogOptions: "dontDisplay"は失敗時にブロッキングエラーボックスを表示することがあります。 エージェントが実行するすべてのデスクリプタには、_options: { dialogOptions: "silent" }を記述する必要があります。ポーリングがタイムアウトした場合は、まずPSがエラーボックスを表示していないか確認し、盲目的に再実行しないでください。ダイアログが表示されている場合は、次のスクリプトを起動しないでください。 -
履歴の読み取りにはDOMを使用し、batchPlay
gethistoryStatesCountは使用しないでください。 後者は「命令「取得」は現在利用できません。」というエラーになります。dontDisplayの場合はポップアップが表示され、silentの場合はresult: -25920が返ります。doc.historyStates/doc.activeHistoryStateを使用してください。 -
非アクティブドキュメントに対する
setは失敗します(「命令「設定」は現在利用できません。」)。最初にターゲットをapp.activeDocumentに設定してからsetを実行してください。同じ構文のmakeレイヤーは非アクティブドキュメントに対しても機能し、現在のドキュメントを切り替えません。デスクリプタ内のドキュメント_idはガードに含める必要があります。 -
マルチレイヤーストロークは
frameFXMultiを使用する必要があります(単一のストロークはframeFXを使用可能)。形状の外側に沿ったグラデーションはgradientType: "shapeburst"を使用します。 -
innerShadow単体キーは静かに無視されます。innerShadowMulti: [{ _obj: "innerShadow", ... }]と記述する必要があります。変更後はgetでlayerEffectsを読み戻し、キーが実際に存在することを確認してください。 -
カスタムパス: まず
setworkPathを実行してからmake contentLayerを実行します。この方法で作成された形状には通常keyOriginTypeがなく、プロパティパネルで角丸を変更できるリアルタイム形状ではありません。編集可能な角丸を作成するには、make contentLayer+shape._obj = "rectangle"/"ellipse"を使用し、unitValueQuadVersion: 1と4つの角の半径を指定します。 -
フォントは PostScript 名 で指定します(例:
textItem.characterStyle.font = "MuseoSansRounded-1000")。フォントがインストールされている必要があります。ユーザーがインストールしたもので十分であり、マシンレベルでインストールする必要はありません。 -
RGB デスクリプタの緑のフィールド名は
grainであり、greenではありません。この名前を「修正」しないでください。 -
executeAsModalは必ずawaitする必要があります。省略すると、後続のコードはモーダルが取得される前に実行されてしまいます。 -
ユーザーがキャンセルすると、
batchPlayは例外をスローします。空のcatchでキャンセルを飲み込まないでください。そうしないとスクリプトが停止しなくなります。
レイヤースタイルと形状の actionJSON は references/batchplay.md を参照。
8. ソース資料
公式:
- UXP Scripting in Photoshop(
.psjs、23.5、起動方法) - Quickstart
- How it works(トップレベル await、モジュール権限、FAQ: 初回リリースではパラメータ渡し非サポート、スクリプト間呼び出し不可、ネットワークなし)
- Scripting reference(
executionContext/hostControl) require("uxp").script(args、setResult)- executeAsModal
- batchPlay
- FileSystemProvider
- File access
- Samples
上記各節の実測補足は、.psjs を使用してUIコンポーネントをバッチ生成し、ゴールデンイメージとピクセルレベルで比較した作業からの知見です。Adobe の標準ではありません。
9. エージェントスライスワークフロー
インターフェースをゲームエンジンにインポート可能な1x PNGにスライスし、コンポーネントセマンティクスに従って整理された、エンジン非依存の中間レイアウトJSONを生成します。詳細、スキーマ、命名規則、識別方法、実測結果は references/slicing.md を参照してください。まず、そのドキュメント冒頭の決定木に従って進めてください: 材料を開く(グループ上のレイヤーエフェクトを含む、影響を受ける各パーツにエフェクト方式を選択)→ コンポーネントの識別 → 共有パーツと状態変化パーツの分別 → バリアントと旧デザインの区別 → 変化するパーツのみに missing を記録 → 繰り返し要素が再利用可能かの判断 → レビューゲートで停止。スクリプトとPythonヘルパー: examples/export_slices.psjs、examples/slicing_helper.py、examples/naming_rules.example.json、examples/export_config.example.json。
Python 環境: プロジェクトの venv を使用してヘルパーを実行し、パッケージをシステム Python にインストールしないでください。psd-tools[composite]、Pillow、numpy が必要です。大きなドキュメントを開くには、確認済みの PSDImage.open(path, parse_limits=ParseLimits(max_objects=None)) を使用してください(パラメータを推測したり、ParseLimits.max_objects クラス属性を設定したりしないでください)。詳細は slicing.md の「Python 環境」を参照。
役割分担: ヘルパーは材料のみを準備します(デフォルト状態の全体図、ID付きのレイヤーごとの切り抜き画像、非表示レイヤーを含むレイヤーツリー、9パッチ候補)。このスキルを実行するエージェントは、これらの材料を同時に読み取り、マニフェストを作成します: コンポーネント、パーツ、標準名、タイプ、状態、階層。--rules はオプションのプロジェクト命名規則にすぎません。infer はキーワードの草案(draft_manifest.json)を生成できますが、エージェントによるリストの代わりにはなりません。
フロー(確認前にエクスポートしない):
- 材料の準備(オフライン):
prepareを実行。--artboard <アートボード名またはID>はオプション。省略した場合、可視のトップレベルアートボードすべてを処理します。アートボードがない場合はキャンバス全体を処理します。ツリーには非表示レイヤー(visibleマーク付き)が含まれます。crops/は主にエクスポート可能なリーフです。レイヤーエフェクトを持つグループはgroup_effects.jsonとcrops_index.jsonに書き込まれます(合成可能な場合はグループ切り抜き画像も含む)、さらに psd-tools から読み取ったエフェクトパラメータeffect_params(タイプ、ブレンドモード、色、不透明度、角度、距離、サイズ、拡張/チョーク、ストローク位置)が付属します。IDはインデックスで検索し、ファイル名を推測しないでください。グループIDに切り抜き画像がない場合、内部のリーフを直接使用しないでください。まず、そのグループにエフェクトがあるかどうかを確認します。エフェクトのないグループ、空のレイヤー、またはアートボード外にあるものは、tree.jsonで判断します。切り抜き画像がないことが、状態が欠落していることを意味するわけではありません。 - エージェントによるマニフェスト作成: タブグループ、ボトムバー、ボタン、リスト行などのインタラクティブコンポーネントを識別します。ベース/ハイライト/アイコン/テキストを状態ごとに独立したパーツに分割し、状態をひとまとめにしないでください。まず、デザイン内でどのパーツが状態間で共有され、どのパーツが変更されるかを確認します。共有されるものは
sharedに配置します(ファイル名に状態サフィックスは付けません)。変更されるものは各statesに配置します。非表示レイヤーは、ベース/コンテンツが同じで、違いが状態スタイル(明度、ストローク、グロー、配色など)のみである場合にのみ、代替状態として扱います。同じスロットに異なるコンテンツやバッジが配置されている場合は、古いデザインとして無視し、それを共有の真のリソースとして代用したり、共有パーツをmissingとして書き出したりしないでください。現在の選択項目スロットにあり、同じ主体でグロー/ハイライトスタイルのみが異なる非表示レイヤーは、その状態のhighlightとして扱う必要があります(デフォルトの選択状態も含む)。可視の選択状態のベースの上に重なるグロー/バブルレイヤーは、形状が異なっていても、置き換えではなく重ね合わせのハイライトです。uncertain_hiddenに含めないでください。コンテンツやモチーフが一致しない場合のみuncertain_hiddenを書き出します(その際は両方の切り抜き画像を含めます)。missing は、同じグループ内で最も完全な項目をテンプレートとして使用します(例: 選択状態の項目に base + highlight + label がある場合、そのうちの1つが欠如している兄弟項目すべてをリストアップします。highlight も含みます)。単一の特別なスタイルのリスト行は、その行の1つのインスタンスにすぎません。他の行に欠落状態を推測したり、この1行に欠落したnormalを推測したりしないでください。ただし、デザイン内のすべての行に完全なバリアントセットがある場合は除きます。エクスポートターゲットを選択する際、その要素の最も近い親グループ(またはその要素を表すグループ)にレイヤーエフェクト(ドロップシャドウなど)があるかどうかを確認します。エフェクトがグループにあり、内部のリーフにはない場合、そのパーツにeffect_modeを選択します(slicing.md「グループエフェクト: ベイク vs エンジン描画」を参照):baked(デフォルト)——layer_id/select_idsにはグループIDを使用し、エフェクトは画像にベイクされます。可視のバウンディングボックスはエフェクトを含み、論理バウンディングボックスは含みません。engine——select_idsには子レイヤーを使用し、グループのeffect_paramsをengine_effectsにコピーし、エンジンが描画します。画像にはエフェクトピクセルは含まれません。このようなパーツごとにeffect_reasonを1行記述します。プロジェクトルールまたはユーザーが方式を指定した場合は、それに従います。唯一禁止されているのは、子レイヤーのみを選択してエフェクトを記録しないことです(エフェクトが静かに失われます)。捏造は禁止です。繰り返し要素は、UIの用途、ゲームUIの常識(リスト行のベース、アバターフレーム、同じタイプのボタン、ランクメダル、通貨アイコン、プログレスバーは通常再利用されます。アバター画像はランタイムコンテンツであり、フレームとは分離してplaceholder: trueとマークする必要があります。名前/スコア/数字は動的テキストです)、およびreuse_candidates.jsonの証拠に基づいて、再利用可能かどうかを判断します。再利用可能な場合は1枚をエクスポートし、各インスタンスにreuse_of: <共有名>と記述します(共有名にインスタンス番号は付けません)。エフェクト画像と一致しない場合は、まず判断が間違っている可能性を疑い、一致しないインスタンスのみを分離してエクスポートします。論理的証拠が強いにもかかわらず一致しない場合、またはアバターとフレームがPSD内で結合されている場合は、reuse_decisionsに書き込みます(証拠、問題点、比較画像、オプション)。ユーザーに決定を委ね、決定まではデフォルトで分離してエクスポートします。命名はモジュール_タイプ_用途_状態(小文字。共有パーツは状態セグメントを省略)とし、PSDのレイヤー名をそのまま使用しないでください。タイプ:image|nine_slice|dynamic_text|art_text。 - レビューゲート:
flatten+previewで注釈付きプレビューとJSONを生成します(タグにfx:baked/fx:engineを含み、エンジンエフェクトはおおよその範囲を描画するため、ユーザーはレビュー中に方式を変更できます。flattenはeffect_issues内でエフェクトが失われるパーツをリストします)。ユーザーがJSONを変更して確認します。確認前はstatusはpending_reviewのままです。previewは反転または空のバウンディングボックスをスキップして警告を表示しますが、そのために中断しないでください。 - エクスポート(
.psjs): スクリプトは1つのCONFIG_URLのみをハードコードし、ジョブJSONからパスを読み取ります。layer_id/select_idsに従って1x PNGをエクスポートします。bakedはグループを選択し、エフェクトは画像にベイクされます。engineは子レイヤーを選択してマージし、画像にはグループエフェクトは含まれません。reuse_ofを持つインスタンスは共有画像を1枚のみエクスポートし、残りのインスタンスはバウンディングボックスのみを記録します。dynamic_textは画像を生成せず、テキストプロパティのみをエクスポートします。art_textは画像を生成します。
…
[翻訳のために切り詰められました]