Usar scripts UXP (.psjs) para controlar Photoshop
Recetas ejecutables para agentes: crear, modificar y exportar documentos en Photoshop. Los hechos se dividen en dos categorías:
- Oficial: de la documentación de Adobe UXP, con enlaces al final.
- Probado: experiencia probada con
.psjsen Windows y macOS, Adobe Photoshop 2026. Lo no verificado se marca como no verificado, no lo trates como API oficial.
Criterio de éxito: El script escribe un JSON de resultado (con done / ok / fatal / errs); solo modifica el documento objetivo especificado por la tarea, sin afectar a otros documentos abiertos; cuando se requiere alineación de píxeles, exporta PNG y lo compara con una imagen de referencia (ΔE / diferencia de píxeles) para iterar.
Detente primero: Si la tarea no especifica qué documento modificar, o si se pide sobrescribir un documento con cambios no guardados del usuario sin permiso explícito.
1. Cuándo usar / Cuándo no usar
Usa .psjs cuando:
- Necesites Photoshop para hacer algo: renderizar píxeles con efectos de capa, exportar capas como slices, usar
batchPlaypara crear formas/texto/efectos, o guardar resultados como PSD/PNG. - Inferir una lista de slices de un PSD/PSB, revisarla y exportar PNGs 1x y un JSON de diseño independiente del motor: ver sección 9.
- El agente necesita ejecutar una tarea de una sola vez (escribir script → iniciar → sondear logs → copiar resultados), sin necesidad de un panel persistente.
No inicies Photoshop cuando:
- Solo necesites leer el árbol de capas, nombres, IDs, texto o límites aproximados: usa
psd-toolsoag-psdpara análisis offline. Probado:layer_iddepsd-toolscoincide conlayer.idde UXP, por lo que se puede usar la estructura offline para localizar, dejando solo el renderizado/exportación a PS. Ten en cuenta que el bbox de psd-tools no incluye efectos de capa; los límites visuales finales deben calcularse en PS.
Usa un plugin UXP cuando:
- Necesites persistencia, comunicación bidireccional (por ejemplo, un puente MCP, un panel, WebSocket). Oficial: los scripts no tienen manifest / panel; Network, LaunchProcess, WebView, IPC no están disponibles. Estas capacidades requieren un plugin y declarar los permisos en el manifest.
- Oficial: no se puede llamar a otro
.psjsdesde un plugin; pero el código UXP de un script generalmente se puede ejecutar dentro de un plugin.
Usa ExtendScript / JSX cuando:
- El objetivo sea Photoshop 23.5 o inferior, o solo se pueda usar
DoJavaScriptde Windows COM /do javascriptde AppleScript en macOS /evalScriptde CEP. JSX es ES3, API síncrona, en modo mantenimiento. No confundaspsx.jsx(la biblioteca auxiliar de ExtendScript de xbytor) con un runtime.
2. Puntos oficiales clave (recuérdalos primero)
- Los scripts UXP independientes están disponibles desde Photoshop 23.5, con extensión
.psjs. Se pueden depurar con UXP Developer Tool ≥ 1.6, pero no se requiere UDT para ejecutar scripts. - Formas oficiales de iniciar:
File > Scripts > Browse...; arrastrar el.psjsal icono del Dock (Mac) o a un área de la ventana de Photoshop que no sea un documento abierto (Mac/Win); reproducir un script con una Acción. Hacer doble clic para abrir se ha marcado como "Próximamente". - El script es JS moderno, soporta
awaitde nivel superior. Los ejemplos oficiales y las pruebas dependen de ello; no escribas "definirasync mainsin que nadie hagaawait main()" y luego salgas inmediatamente. - Cualquier operación que modifique el documento o el estado de la aplicación debe envolverse en
require("photoshop").core.executeAsModal(fn, { commandName }).commandNamese muestra en la barra de progreso (aparece si el script dura más de ~2-3 segundos, el usuario puede cancelar). - Cuando el DOM no sea suficiente, usa
require("photoshop").action.batchPlay(descriptors, options). Los descriptores son actionJSON. La documentación oficial recomienda priorizar el DOM. Usa "Copy As JavaScript" del panel Actions en modo desarrollador, o graba descriptores conPlugins > Development > Record Action Commands..., no inventes nombres de clave. dialogOptionsse escribe en_optionsde cada descriptor, con valores"silent"(por defecto, sin diálogos aunque haya errores),"dontDisplay"(generalmente sin diálogos, pero puede mostrar si faltan parámetros o hay errores),"display". Probado (PS 2026): el agente debe usar"silent"."dontDisplay"aún puede mostrar cuadros de error bloqueantes cuando un comando falla (ej.Comando "Obtener" no disponible actualmente.); el script esperará hasta que alguien haga clic en "Aceptar"; al hacerlo, devuelve{_obj:"error", message:"", result:-128}(-128 es el código de cancelación del usuario oficial)."silent"no muestra diálogos, devuelve{_obj:"error", message:"Nombre del script: Comando "…" no disponible actualmente.", result:-25920}en ~1-5ms. Se ha probado pasar{ dialogOptions: "dontDisplay" }como segundo argumento debatchPlaysin error, pero la tabla de opciones oficial no tiene esa clave, y no se puede verificar de forma segura con"display"si funciona. El código nuevo debe escribirdialogOptionsen_optionsdel descriptor, usando"silent".- Parámetros ilegales en
batchPlayprovocan un rechazo; fallos en tiempo de ejecución (objetivo no existe etc.) resuelven, devolviendo{_obj:"error", message, result}.result === -128significa que el usuario canceló. Siempre revisa el array devuelto. - Sistema de archivos: los scripts no tienen manifest, los permisos los otorga Photoshop. La documentación de scripts aún dice: puedes usar selectores de archivos y
getTemporaryFolder().getEntryWithUrl/createSessionTokenson parte de la API FileSystemProvider oficial (ver sección 4 para pruebas). require("uxp").scriptproporcionaexecutionContext,args,setResult(result). Las FAQ oficiales (notas de lanzamiento inicial) decían: la primera versión no soporta pasar argumentos al script. No confíes en argumentos de línea de comandos oscript.argspara pasar la configuración de la tarea; escribe la ruta y los parámetros en el script, o haz que el script lea un JSON adyacente. Probado (Windows / PS 2026,Photoshop.exe script.psjs):script.argses[]. Si se añaden más argumentos CLI después de la ruta del script, el script no se ejecuta (sin archivo de resultado en 3 minutos), el lanzador sigue devolviendo inmediatamente con código de salida 0 y stdout vacío. No pases argumentos CLI adicionales.setResultse puede llamar, devuelveundefined, y no aparece en el código de salida ni en stdout dePhotoshop.exe. Usa siempre un archivo de resultado.- Solo se puede ejecutar un script a la vez, y un script no puede llamar a otro script.
executionContextoficial:isCancelled/onCancelpara responder a la cancelación del usuario,reportProgress({ value, commandName })para actualizar la barra de progreso,hostControl.suspendHistory({ documentID, name })+resumeHistory(id, commit)para agrupar varias modificaciones en un solo paso de historial, facilitando la reversión del diseñador. Probado:isCancelledes booleano;reportProgressse puede llamar, devuelveundefined.suspendHistory({documentID, name})devuelve{historySuspensionID},resumeHistory(id)agrupa las modificaciones posteriores en un paso, cuyo nombre aparece endoc.historyStates. Las claves enumerables dehostControlpueden estar vacías; usaObject.getOwnPropertyNames. Lee el historial usando el DOM (doc.historyStates/doc.activeHistoryState), nobatchPlaygethistoryStatesCount(ese comando no está disponible, ver sección 7).
3. Inicio y sondeo por parte del agente (probado en Windows)
Oficialmente, no hay una interfaz documentada para "pasar un .psjs a Photoshop.exe por línea de comandos". Probado (Windows / Photoshop 2026):
& "C:\Program Files\Adobe\Adobe Photoshop 2026\Photoshop.exe" "D:\work\ps-job\run_job.psjs"
- No requiere Creative Cloud Desktop, UDT ni modo desarrollador.
- Si Photoshop ya está abierto, el script se ejecuta en la instancia existente.
- El lanzador devuelve inmediatamente, el script continúa ejecutándose asíncronamente en PS. Debes sondear el JSON de resultado escrito por el script (que debe contener
done,ok,fatal,errs), no confíes en el código de salida del proceso para determinar el éxito o fracaso. - Se probó: un script de exportación tardó unos 18 segundos en exportar un
.psben 28 slices (abrir el archivo tomó ~10 segundos) y escribirexport_log.json. - Probado (Windows / PS 2026): La asociación de archivos existe (
.psjs=Photoshop.PSJSFileType.200, ftype esPhotoshop.exe "%1").Start-Process script.psjsejecutará el script y escribirá el archivo de resultado. El agente aún debe pasar explícitamentePhotoshop.exe+ la ruta del script, y basarse en el archivo de resultado. - Antes de iniciar, asegúrate de que PS no tenga un cuadro de diálogo modal abierto (diálogos de "Recuperar documento" después de un bloqueo, diálogos de guardado, etc.). Si hay un diálogo abierto, el script no se ejecutará como se espera y el sondeo solo dará timeout; en caso de timeout, primero captura la pantalla de PS para ver la interfaz, no reinicies ciegamente el script.
Flujo de trabajo remoto para el agente: Escribir el .psjs en el lado del agente → Copiarlo a la máquina con Photoshop (solo usando directorios autorizados por el usuario) → Iniciar con el shell y sondear los logs → Copiar los PNG/PSD/logs de vuelta → Hacer comparación de píxeles si es necesario.
Ejemplo de sondeo (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 esperando $log" }
} while ($true)
macOS (probado, Photoshop 2026, Mac mini): La documentación oficial solo menciona arrastrar al Dock/ventana; el siguiente inicio por línea de comandos no está documentado oficialmente, pero se ha probado que funciona:
open -a "Adobe Photoshop 2026" /path/to/run_job.psjs
# Si la asociación .psjs está configurada, también: open /path/to/run_job.psjs
- Inicio en frío: PS no se está ejecutando,
open -adevuelve ~0.3 segundos (exit 0), PS se inicia y ejecuta el script automáticamente, escribiendo el archivo de resultado en ~8 segundos. - Inicio en caliente: PS ya se está ejecutando, el script se ejecuta en la instancia existente y escribe el resultado en unos segundos.
open xxx.psjssin-a, usando la asociación de archivos, también ejecuta el script.getEntryWithUrl("file:/Users/<user>/...")puede escribir archivos sin un selector de archivos.- Igual que en Windows: el lanzador devuelve inmediatamente, debes sondear el archivo de resultado y no agregar argumentos CLI adicionales.
Ejemplo de sondeo (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"
El script esqueleto está en examples/run_job.psjs (await de nivel superior, executeAsModal, protección de ID de documento, archivo de resultado, try/catch). Probado: con este esqueleto funciona: escribe done/ok, exporta preview.png, cierra los documentos que creó, y el conjunto de IDs de otros documentos abiertos permanece sin cambios.
4. Acceso a archivos
FileSystemProvider oficial: getFileForOpening / getFileForSaving / getFolder, getTemporaryFolder, getEntryWithUrl(url), createEntryWithUrl, createSessionToken(entry).
El _path para batchPlay debe ser un session token, no una ruta de sistema sin formato. Oficial: al usar el DOM de Photoshop (ej. app.open(file), doc.saveAs.psd(file, …)), se puede pasar directamente una entrada File/Folder, el host la convierte automáticamente en token.
Probado (PS 2026 script, sin selector de archivos):
const fs = require("uxp").storage.localFileSystem;
const root = await fs.getEntryWithUrl("file:/D:/work/ps-job"); // El directorio debe existir
const out = await root.createFile("job_log.json", { overwrite: true });
await out.write(JSON.stringify(log, null, 2));
Las URLs como file:/D:/... funcionan en Windows. La documentación de scripts aún solo garantiza selector + directorio temporal; trata "cualquier ruta, sin selector" como comportamiento probado en PS 2026, y haz una prueba de escritura de archivo al cambiar de versión. No llames a módulos de red; el entorno de scripts oficial lo prohíbe.
5. Ámbito y seguridad del documento (obligatorio)
Principio: El script solo toca el documento objetivo especificado por la tarea. El objetivo puede ser un documento nuevo creado por el script, o un PSD existente mencionado por la tarea (iterar sobre un diseño existente es un escenario común). No modifiques, guardes ni cierres ningún otro documento abierto.
Determina el conjunto objetivo targets:
- Nuevo: el ID devuelto por
app.createDocument()se añade atargets. - Iterar sobre un PSD existente: localízalo por la ruta dada en la tarea. Primero busca en
app.documentspordoc.pathpara ver si ya está abierto; si lo está, usa esa instancia directamente (no abras una segunda copia); si no, usaapp.open(entry). No te fíes solo del nombre (puede haber duplicados, copias "-Recuperado"); prioriza la ruta, luego el ID de documento dado en la tarea. Probado: usar la ruta permite reutilizar la misma instancia (mismo ID de documento, no se abre una segunda copia); después de editar sin guardar,doc.saved === false; al usarsaveAs(..., true)para guardar una nueva versión, el mtime y tamaño del archivo original no cambian, el documento permanece abierto y apunta a la ruta original. En Windows,doc.pathtiene el formatoD:\work\file.psd. Los documentos recuperados (ej. "xxx-Recuperado") pueden tenerpathvacío,saved === false, y no se pueden encontrar por ruta; usa el ID de documento dado en la tarea. - Los documentos temporales (ej. slices creados desde "Nueva capa") se añaden a
targetsy se cierran concloseWithoutSaving()cuando ya no se necesiten.
Protección: Antes de cada batchPlay, guardado o cierre, verifica que app.activeDocument.id esté en targets. Esta verificación solo cubre los descriptores que "apuntan implícitamente al documento actual"; los descriptores que tienen explícitamente { _ref: "document", _id } también deben verificar ese ID. Registra app.documents.map(d => ({ name: d.name, id: d.id, path: d.path })) antes y después de la ejecución, y escríbelo en el log.
Probado: al usar make en una capa con { _ref: "document", _id } de un documento no activo, la capa se crea en ese documento, y activeDocument no cambia; por lo tanto, debes verificar los IDs explícitos. Sin embargo, set no funciona en documentos no activos (ver sección 7); para cambiar propiedades, primero haz app.activeDocument = target y luego set.
Al modificar un documento existente:
- Si el documento objetivo ya está abierto y tiene cambios sin guardar (
doc.saved === falseoficialmente), significa que el usuario lo está editando manualmente. Por defecto, puedes continuar editando sobre él (este es el caso típico de iteración), pero no sobrescribas el archivo guardando, a menos que la tarea lo solicite explícitamente; primero registra en el log que estaba sucio antes de la ejecución. - Usa
hostControl.suspendHistorypara agrupar las modificaciones del script en un solo paso de historial, para que el usuario pueda deshacerlo con un solo Ctrl+Z. - La estrategia de guardado depende de la tarea: por defecto, guarda una nueva versión (ej.
xxx_v14.psd), conservando el archivo original; solo usadoc.save()si la tarea solicita explícitamente "actualizar en el mismo lugar". - Al final del script, no cierres los documentos objetivo que el usuario haya abierto originalmente; solo cierra los documentos que el script abrió o creó y que la tarea no requiere conservar.
Limpieza automática: executionContext.hostControl.registerAutoCloseDocument(docID) oficial cierra automáticamente documentos temporales cuando el usuario cancela o termina el modal; solo úsalo para documentos nuevos creados por el script. Si quieres que el diseñador los edite después, usa unregisterAutoCloseDocument primero. No registres documentos existentes del usuario para cierre automático.
6. Ciclo de verificación
- El script exporta PNG (y opcionalmente guarda PSD).
- En el lado del agente, compara con la imagen de referencia (CIEDE2000 ΔE, diferencia de píxeles, ampliación local).
- Según las diferencias, modifica el script (rutas, degradados, efectos de capa); no edites manualmente sobre el documento del usuario y esperes que sea reproducible.
- Vuelve a ejecutar, exportar, comparar; hasta que se cumpla el estándar o se explique la diferencia restante.
7. Problemas probados
-
dialogOptions: "dontDisplay"aún puede mostrar cuadros de error bloqueantes cuando falla. Cada descriptor ejecutado por el agente debe tener_options: { dialogOptions: "silent" }. Si el sondeo expira, primero verifica si PS mostró un cuadro de error; no reinicies ciegamente el script. Si hay un diálogo abierto, no inicies el siguiente script. -
Lee el historial con el DOM, no con
batchPlaygethistoryStatesCount. Esto último da el error "Comando "Obtener" no disponible actualmente."dontDisplaymuestra un diálogo,silentdevuelveresult: -25920. Usadoc.historyStates/doc.activeHistoryState. -
seten un documento no activo falla ("Comando "Establecer" no disponible actualmente."). Primero establece el objetivo comoapp.activeDocumenty luego hazset. Por otro lado,makede capa puede funcionar en un documento no activo sin cambiar el documento actual; el_iddel documento en el descriptor debe incluirse en la protección. -
Trazo múltiple debe usar
frameFXMulti(un solo trazo puede usarframeFX). El degradado que se extiende alrededor de la forma usagradientType: "shapeburst". -
innerShadowde una sola clave se ignora silenciosamente, debe escribirse comoinnerShadowMulti: [{ _obj: "innerShadow", ... }]. Después de modificar, usagetpara leerlayerEffectsy verifica que la clave esté realmente presente. -
Rutas personalizadas: primero
setworkPath, luegomake contentLayer. Las formas creadas así generalmente no tienenkeyOriginType, no son formas en tiempo real con esquinas redondeadas editables en la barra de propiedades. Para esquinas redondeadas editables, usamake contentLayer+shape._obj = "rectangle"/"ellipse"conunitValueQuadVersion: 1y los cuatro radios de esquina. -
Las fuentes se asignan por nombre PostScript (ej.
textItem.characterStyle.font = "MuseoSansRounded-1000"), y deben estar instaladas; solo el usuario debe instalarlas, no es necesario instalarlas a nivel de sistema. -
En los descriptores RGB, el campo verde se llama
grain, nogreen. No "corrijas" este nombre. -
executeAsModaldebe serawait. Si falta, el código posterior se ejecutará antes de que el modal esté activo. -
Después de que el usuario cancele,
batchPlaylanzará una excepción; no hagas uncatchvacío que trague la cancelación, o el script no se detendrá.
El actionJSON de efectos de capa y formas está en references/batchplay.md.
8. Fuentes de información
Oficial:
- UXP Scripting in Photoshop (
.psjs, 23.5, formas de inicio) - Quickstart
- How it works (
awaitde nivel superior, permisos de módulos, FAQ: sin soporte de argumentos en la primera versión, no se pueden llamar scripts desde scripts, sin red) - Scripting reference (
executionContext/hostControl) require("uxp").script(args,setResult)- executeAsModal
- batchPlay
- FileSystemProvider
- File access
- Samples
Las pruebas complementarias están en las secciones anteriores, basadas en el trabajo de crear componentes de UI por lotes con .psjs y comparar píxeles con la imagen de referencia, no en el estándar de Adobe.
9. Flujo de trabajo de slicing para el agente
Corta la interfaz en PNGs 1x que un motor de juegos pueda importar, y genera un JSON de diseño intermedio independiente del motor, organizado por semántica de componentes. Los detalles, esquema, reglas de nomenclatura, métodos de identificación y pruebas están en references/slicing.md. Sigue primero el árbol de decisión al inicio de ese documento: Abrir el material (incluyendo efectos de capa en grupos, y elegir el modo de efecto para cada componente afectado) → Identificar componentes → Separar partes compartidas y que cambian por estado → Distinguir variantes de borradores antiguos → Solo marcar como "missing" las partes que cambian → Decidir si los elementos duplicados se reutilizan → Detenerse en la puerta de revisión. Scripts y ayudas de Python: examples/export_slices.psjs, examples/slicing_helper.py, examples/naming_rules.example.json, examples/export_config.example.json.
Entorno Python: Ejecuta la ayuda en el venv del proyecto, no instales paquetes en el Python del sistema. Necesita psd-tools[composite], Pillow, numpy. Para abrir documentos grandes, usa PSDImage.open(path, parse_limits=ParseLimits(max_objects=None)) (no adivines parámetros, ni establezcas ParseLimits.max_objects como atributo de clase). Ver slicing.md "Entorno Python".
División del trabajo: La ayuda solo prepara material (imagen completa del estado por defecto, recortes por capa con ID, árbol de capas con capas ocultas, candidatos para nine-slice). El agente que ejecuta esta habilidad lee estos materiales y escribe el manifiesto: componentes, partes, nombres estandarizados, tipos, estados y jerarquía. --rules es solo una convención de nomenclatura opcional para el proyecto. infer aún puede producir un borrador de palabras clave (draft_manifest.json), pero no puede reemplazar la lista del agente.
Flujo de trabajo (no exportes antes de confirmar):
- Preparar material (offline):
prepare.--artboard <nombre o id del artboard>es opcional; si se omite, procesa todos los artboards superiores visibles; si no hay artboards, procesa todo el lienzo. El árbol incluye capas ocultas (marcadasvisible).crops/son principalmente hojas exportables; los grupos con efectos de capa se escriben engroup_effects.jsonycrops_index.json(con recorte de grupo si es componible), y se adjuntan los parámetros de efecto leídos por psd-tools (effect_params: tipo, modo de mezcla, color, opacidad, ángulo, distancia, tamaño, extensión/contracción, posición del trazo). Usa el índice para buscar IDs, no adivines nombres de archivo. Si un grupo no tiene recorte, no uses directamente una hoja interna; primero mira si el grupo tiene efectos. Los grupos sin efectos, capas vacías o fuera del artboard, se evalúan entree.json; no tener recorte no significa estado faltante. - El agente escribe el manifiesto: Identifica componentes interactivos como pestañas, barras inferiores, botones, filas de lista, etc. Separa fondos/destacados/iconos/texto en partes independientes según el estado, no hornees los estados juntos. Primero mira qué partes del diseño se comparten entre estados y cuáles cambian: lo compartido va en
shared(nombre de archivo sin sufijo de estado), lo que cambia va enstatesrespectivos. Las capas ocultas solo cuentan como estado alternativo si el cuerpo/contenido principal no cambia y la diferencia es solo estilo de estado (brillo, trazo, resplandor, esquema de color, etc.); si la misma ranura tiene contenido o insignia diferente, trátalo como un borrador antiguo e ignóralo, no lo uses para reemplazar el recurso compartido real, ni marques las partes compartidas como missing. Las capas ocultas que están en la ranura del elemento seleccionado actualmente y que solo difieren en estilo de resplandor/destacado, deben considerarse comohighlightde ese estado (el estado seleccionado por defecto también debe incluirse); las capas de resplandor/burbuja superpuestas sobre un fondo seleccionado visible, incluso si tienen una forma diferente, son un resaltado superpuesto, no un reemplazo, no las pongas enuncertain_hidden; solo escribeuncertain_hiddensi el contenido o el motivo no coinciden (incluyendo los recortes de ambos lados). Los elementos "missing" deben usar como plantilla el elemento más completo del mismo grupo (ej. el elemento seleccionado tiene base + highlight + label), y listar cada hermano que carezca de una de esas piezas, incluyendo highlight. Una fila de lista con un estilo especial es solo una instancia de esa fila; no infieras estados faltantes para otras filas, ni infieras un normal faltante para esta fila, a menos que el diseño tenga conjuntos de variantes para cada fila. Al seleccionar el objetivo de exportación, verifica si el grupo padre más cercano del elemento (o el grupo que lo representa) tiene efectos de capa (como sombra). Si el efecto está en el grupo y las hojas internas no lo tienen, elige uneffect_modepara esa parte (ver slicing.md "Efectos de grupo: horneado vs. motor"):baked(por defecto) —layer_id/select_idsusan el ID del grupo, el efecto está horneado en la imagen, el cuadro visible incluye el efecto, el cuadro lógico no;engine—select_idsusan las subcapas, loseffect_paramsdel grupo se copian enengine_effects, el motor los renderiza, la imagen no contiene píxeles de efecto. Cada parte así escribe una líneaeffect_reason. Si las reglas del proyecto o el usuario especifican un modo, hazlo. Lo único prohibido es seleccionar solo la subcapa sin registrar el efecto (el efecto se pierde silenciosamente). Prohibido inventar. Los elementos duplicados se evalúan según el propósito de la UI, el sentido común de la UI de juegos (bases de filas de lista, marcos de avatar, botones del mismo estilo, medallas de clasificación, iconos de moneda, barras de progreso generalmente se reutilizan; las imágenes de avatar son contenido en tiempo de ejecución, deben separarse del marco y marcarse conplaceholder: true; los nombres/puntuaciones/números son texto dinámico) y la evidencia enreuse_candidates.json. Si se deben reutilizar, exporta una sola imagen y cada instancia escribereuse_of: <nombre_compartido>(el nombre compartido no lleva número de instancia); si no coincide con la imagen de efecto, primero sospecha que la decisión es incorrecta y solo separa las instancias inconsistentes; si la evidencia lógica es sólida pero no coincide, o si el avatar y el marco están combinados en el PSD, escribe enreuse_decisions(evidencia, problema, imágenes de comparación, opciones) y deja que el usuario decida; por defecto, antes de decidir, exporta por separado. Nombra comomódulo_tipo_función_estado(minúsculas; las partes compartidas omiten el segmento de estado), no uses directamente los nombres de las capas del PSD. Tipos:image|nine_slice|dynamic_text|art_text. - Puerta de revisión:
flatten+previewproduce una vista previa anotada y un JSON (las etiquetas incluyenfx:baked/fx:engine, los efectos del motor dibujan un rango estimado para que el usuario pueda cambiar el modo durante la revisión;flattenenumerará eneffect_issueslas partes que perderán efectos). El usuario modifica el JSON y lo confirma;statuspermanecepending_reviewantes de la confirmación.previewomitirá los cuadros delimitadores invertidos o vacíos y dará una advertencia, sin interrumpir por ello. - Exportar (
.psjs): El script solo codifica unaCONFIG_URLy lee las rutas del JSON del trabajo. Exporta PNG 1x porlayer_id/select_ids:bakedselecciona el grupo, el efecto se hornea en la imagen;engineselecciona las subcapas y las fusiona, la imagen no contiene efectos de grupo. Las instancias conreuse_ofsolo exportan una imagen compartida; las demás instancias solo registran sus límites.dynamic_textno genera imagen, solo exporta las propiedades del texto;art_textgenera imagen.