UXP 스크립트(.psjs)로 Photoshop 구동하기
에이전트용 실행 가능한 레시피: Photoshop에서 문서를 생성, 수정, 내보냅니다. 사실은 두 가지로 분류됩니다.
- 공식: Adobe UXP 문서에서 가져온 내용으로, 문서 끝에 링크가 있습니다.
- 실측: Windows와 macOS, Adobe Photoshop 2026에서
.psjs로 실행해 본 경험입니다. 확인되지 않은 내용은 미확인으로 표시하며, 공식 API로 간주하지 마십시오.
성공 기준: 스크립트는 결과 JSON(done / ok / fatal / errs 포함)을 작성해야 합니다. 작업에 지정된 대상 문서만 수정하고, 다른 열려 있는 문서는 영향을 받지 않아야 합니다. 픽셀 정렬이 필요한 경우 PNG를 내보내고 골든 이미지와 ΔE/픽셀 차이를 비교하여 반복합니다.
잠시 멈추세요: 작업에서 수정할 문서를 명확히 지정하지 않았거나, 사용자가 저장하지 않은 변경 사항이 있는 문서를 덮어쓰도록 요청하면서 작업이 명시적으로 허용하지 않은 경우입니다.
1. 언제 사용하고 / 언제 사용하지 않는지
.psjs 사용 시:
- Photoshop이 필요한 작업: 레이어 스타일이 적용된 픽셀 렌더링, 레이어별 슬라이스 내보내기, batchPlay로 모양/텍스트/효과 생성, 결과를 PSD/PNG로 저장.
- PSD/PSB에서 슬라이싱 매니페스트를 추론하고, 검토 후 엔진 독립적인 레이아웃 JSON과 1x PNG를 내보내는 경우: 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)으로 드래그; 액션으로 스크립트 실행. 더블 클릭은 "Coming soon"으로 표시되었습니다. - 스크립트는 최신 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"는 명령이 실패할 경우 여전히 차단 오류 상자(예:명령 "가져오기"를 현재 사용할 수 없습니다.)를 표시하며, 스크립트는 누군가 확인을 누를 때까지 기다립니다. 확인을 클릭하면{_obj:"error", message:"", result:-128}이 반환됩니다(-128은 공식 사용자 취소 코드)."silent"는 대화상자를 표시하지 않으며 약 1-5ms 후에{_obj: "error", message: "스크립트 이름: 명령 "…"을(를) 현재 사용할 수 없습니다.", result: -25920}을 반환합니다. 이전에는{ dialogOptions: "dontDisplay" }를batchPlay의 두 번째 인수로 전달해도 오류가 발생하지 않았지만, 공식 options 테이블에는 이 키가 없으며"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에 나타나지 않습니다. 항상 결과 파일을 사용하십시오.- 동시에 하나의 스크립트만 실행할 수 있으며, 스크립트는 다른 스크립트를 호출할 수 없습니다.
- 공식
executionContext:isCancelled/onCancel은 사용자 취소에 응답하는 데 사용,reportProgress({ value, commandName })는 진행률 표시줄 업데이트,hostControl.suspendHistory({ documentID, name })+resumeHistory(id, commit)는 여러 수정을 하나의 기록 단계로 그룹화하여 아티스트가 한 번에 취소할 수 있도록 합니다. 실측:isCancelled는 boolean입니다.reportProgress는 호출 가능하며undefined를 반환합니다.suspendHistory({documentID, name})는{historySuspensionID}를 반환하고,resumeHistory(id)는 이후의 여러 수정을 하나의 단계로 그룹화하며 이름이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 "$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로 이미 열려 있는지 확인합니다. 열려 있으면 해당 인스턴스를 바로 사용하고(두 번째로 열지 않음), 열려 있지 않으면app.open(entry)를 사용합니다. 이름만으로 찾는 것은 신뢰할 수 없습니다(중복 이름, "-복구됨" 복사본). 경로를 우선하고, 그 다음으로 작업에 주어진 문서 ID를 사용하십시오. 실측: 경로로 동일한 인스턴스를 재사용할 수 있습니다(동일한 문서 ID, 두 번째로 열리지 않음). 저장되지 않은 편집 후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를 사용하여 이번 스크립트의 수정을 하나의 기록 단계로 그룹화하면 사용자가 한 번의 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및 네 모서리 반경을 사용하십시오. -
글꼴은 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에 넣습니다. 숨겨진 레이어는 본문/내용이 동일하고 차이가 상태 스타일(명도, 테두리, 광선, 색상 등)일 경우에만 대체 상태로 간주합니다. 동일한 슬롯에 있지만 내용이나 엠블럼이 변경된 경우 이전 디자인으로 간주하고 무시합니다. 공유된 실제 리소스를 대체하는 데 사용하지 말고, 공유 파트를 누락된 것으로 작성하지 마십시오. 현재 선택된 항목의 슬롯에 있고 본문이 동일하며 광선/하이라이트 스타일만 다른 숨겨진 레이어는 해당 상태의highlight로 처리해야 합니다(기본 선택 상태도 포함). 표시된 선택된 배경 위에 겹쳐진 광선/말풍선 레이어는 모양이 다르더라도 대체가 아닌 오버레이 하이라이트이므로uncertain_hidden에 넣지 마십시오. 내용이나 주제가 일치하지 않는 경우에만uncertain_hidden을 작성하고(양쪽 크롭 이미지 포함)하십시오. 누락(missing)은 동일한 그룹에서 가장 완전한 항목을 템플릿으로 사용합니다(예: 선택된 항목에 base + highlight + label이 있는 경우). 그중 하나가 누락된 각 형제 항목에 대해 highlight를 포함하여 나열합니다. 특별한 스타일의 단일 목록 행은 해당 행의 인스턴스일 뿐이며, 다른 행에 대해 누락된 상태를 추론하지 말고, 이 행에 대해 누락된 normal을 추론하지 마십시오. 내보내기 대상을 선택할 때 해당 요소의 가장 가까운 상위 그룹(또는 요소를 나타내는 그룹)에 레이어 효과(예: 그림자)가 있는지 확인하십시오. 효과가 그룹에 있고 내부 리프에 없는 경우 해당 파트에 대해effect_mode를 선택합니다(slicing.md "그룹 효과: 베이킹 또는 엔진 렌더링" 참조):baked(기본값) —layer_id/select_ids는 그룹 ID를 사용하고 효과는 이미지에 베이킹되며, 표시되는 경계는 효과를 포함하고 논리적 경계는 포함하지 않습니다.engine—select_ids는 하위 레이어를 사용하고, 그룹의effect_params를engine_effects에 복사하여 엔진이 렌더링하며, 이미지에는 효과 픽셀이 없습니다. 이러한 각 파트에 대해effect_reason을 한 줄씩 작성합니다. 프로젝트 규칙이나 사용자가 방식을 지정한 경우 그대로 따릅니다. 유일하게 금지되는 것은 하위 레이어만 선택하고 효과를 기록하지 않는 것입니다 (효과가 조용히 손실됨). 날조를 금지합니다. 중복 요소는 먼저 UI 용도, 게임 UI 상식(목록 행 배경, 아바타 프레임, 동일한 버튼, 순위 메달, 통화 아이콘, 진행률 표시줄은 일반적으로 재사용됨; 아바타 이미지는 런타임 콘텐츠이므로 프레임과 분리하고placeholder: true로 표시해야 함; 이름/점수/숫자는 동적 텍스트) 및reuse_candidates.json의 증거를 기반으로 재사용 여부를 판단합니다. 재사용해야 하는 경우 하나의 이미지를 내보내고 각 인스턴스에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): 스크립트는 하나의CONFIG_URL만 하드코딩하고 작업 JSON에서 경로를 읽습니다.layer_id/select_ids로 1x PNG를 내보냅니다:baked는 그룹을 선택하고 효과를 이미지에 베이킹합니다.engine은 하위 레이어를 병합하여 선택하며 이미지에 그룹 효과가 포함되지 않습니다.reuse_of가 있는 인스턴스는 하나의 공유 이미지만 내보내고 나머지 인스턴스는 경계만 기록합니다.dynamic_text는 이미지를 내보내지 않고 텍스트 속성만 내보냅니다.art_text는 이미지를 내보냅니다.
…
[번역을 위해 잘림]