CommunityImagengithub.com

younglark/photoshop-psjs

Usa esta habilidad para controlar Adobe Photoshop con scripts UXP independientes (.psjs): escribir, lanzar, sondear y verificar la creación/edición/exportación de documentos desde un agente. Cubre executeAsModal, batchPlay, tokens de archivo, seguridad de ID de documento y la diferencia entre psjs, plugins UXP y ExtendScript/JSX.

¿Qué es photoshop-psjs?

Esta habilidad proporciona un conjunto completo de recetas ejecutables para que un agente de IA pueda controlar Adobe Photoshop de forma programática usando scripts UXP independientes (.psjs). Cubre desde la creación y modificación de documentos hasta la exportación en formatos como PSD o PNG, todo orquestado desde la línea de comandos. Está diseñada para tareas que requieren renderizado pixel-perfect con efectos de capa, exportación de slices y verificación visual iterativa, sin necesidad de una interfaz de usuario persistente. La habilidad detalla las mejores prácticas basadas en documentación oficial de Adobe y en pruebas realizadas con Photoshop 2026 en Windows y macOS, incluyendo cómo iniciar scripts, sondear resultados mediante archivos JSON, y manejar la seguridad de las IDs de documento para evitar modificar documentos no objetivo. También advierte sobre casos de uso inapropiados, como usar ExtendScript/JSX para versiones antiguas de Photoshop, o Photoshops para tareas de solo lectura que pueden resolverse con bibliotecas como psd-tools. Incluye un flujo de trabajo completo para slicing de interfaces de usuario, con generación de manifiestos de componentes y exportación de PNGs, así como ejemplos de scripts y herramientas auxiliares en Python. Está orientada a agentes que necesitan automatizar flujos de diseño gráfico complejos, como la generación de assets para videojuegos o la iteración sobre diseños existentes.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/younglark/photoshop-skills/tree/HEAD/skills/photoshop-psjs

Installed? Explore more Imagen skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

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 .psjs en 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 batchPlay para 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-tools o ag-psd para análisis offline. Probado: layer_id de psd-tools coincide con layer.id de 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 .psjs desde 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 DoJavaScript de Windows COM / do javascript de AppleScript en macOS / evalScript de CEP. JSX es ES3, API síncrona, en modo mantenimiento. No confundas psx.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 .psjs al 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 await de nivel superior. Los ejemplos oficiales y las pruebas dependen de ello; no escribas "definir async main sin que nadie haga await 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 }). commandName se 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 con Plugins > Development > Record Action Commands..., no inventes nombres de clave.
  • dialogOptions se escribe en _options de 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 de batchPlay sin 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 escribir dialogOptions en _options del descriptor, usando "silent".
  • Parámetros ilegales en batchPlay provocan un rechazo; fallos en tiempo de ejecución (objetivo no existe etc.) resuelven, devolviendo {_obj:"error", message, result}. result === -128 significa 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 / createSessionToken son parte de la API FileSystemProvider oficial (ver sección 4 para pruebas).
  • require("uxp").script proporciona executionContext, 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 o script.args para 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.args es []. 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. setResult se puede llamar, devuelve undefined, y no aparece en el código de salida ni en stdout de Photoshop.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.
  • executionContext oficial: isCancelled / onCancel para 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: isCancelled es booleano; reportProgress se puede llamar, devuelve undefined. suspendHistory({documentID, name}) devuelve {historySuspensionID}, resumeHistory(id) agrupa las modificaciones posteriores en un paso, cuyo nombre aparece en doc.historyStates. Las claves enumerables de hostControl pueden estar vacías; usa Object.getOwnPropertyNames. Lee el historial usando el DOM (doc.historyStates / doc.activeHistoryState), no batchPlay get historyStatesCount (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 .psb en 28 slices (abrir el archivo tomó ~10 segundos) y escribir export_log.json.
  • Probado (Windows / PS 2026): La asociación de archivos existe (.psjs=Photoshop.PSJSFileType.200, ftype es Photoshop.exe "%1"). Start-Process script.psjs ejecutará el script y escribirá el archivo de resultado. El agente aún debe pasar explícitamente Photoshop.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 -a devuelve ~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.psjs sin -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 a targets.
  • Iterar sobre un PSD existente: localízalo por la ruta dada en la tarea. Primero busca en app.documents por doc.path para ver si ya está abierto; si lo está, usa esa instancia directamente (no abras una segunda copia); si no, usa app.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 usar saveAs(..., 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.path tiene el formato D:\work\file.psd. Los documentos recuperados (ej. "xxx-Recuperado") pueden tener path vací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 targets y se cierran con closeWithoutSaving() 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 === false oficialmente), 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.suspendHistory para 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 usa doc.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

  1. El script exporta PNG (y opcionalmente guarda PSD).
  2. En el lado del agente, compara con la imagen de referencia (CIEDE2000 ΔE, diferencia de píxeles, ampliación local).
  3. 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.
  4. 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 batchPlay get historyStatesCount. Esto último da el error "Comando "Obtener" no disponible actualmente." dontDisplay muestra un diálogo, silent devuelve result: -25920. Usa doc.historyStates / doc.activeHistoryState.

  • set en un documento no activo falla ("Comando "Establecer" no disponible actualmente."). Primero establece el objetivo como app.activeDocument y luego haz set. Por otro lado, make de capa puede funcionar en un documento no activo sin cambiar el documento actual; el _id del documento en el descriptor debe incluirse en la protección.

  • Trazo múltiple debe usar frameFXMulti (un solo trazo puede usar frameFX). El degradado que se extiende alrededor de la forma usa gradientType: "shapeburst".

  • innerShadow de una sola clave se ignora silenciosamente, debe escribirse como innerShadowMulti: [{ _obj: "innerShadow", ... }]. Después de modificar, usa get para leer layerEffects y verifica que la clave esté realmente presente.

  • Rutas personalizadas: primero set workPath, luego make contentLayer. Las formas creadas así generalmente no tienen keyOriginType, no son formas en tiempo real con esquinas redondeadas editables en la barra de propiedades. Para esquinas redondeadas editables, usa make contentLayer + shape._obj = "rectangle" / "ellipse" con unitValueQuadVersion: 1 y 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, no green. No "corrijas" este nombre.

  • executeAsModal debe ser await. Si falta, el código posterior se ejecutará antes de que el modal esté activo.

  • Después de que el usuario cancele, batchPlay lanzará una excepción; no hagas un catch vací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:

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):

  1. 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 (marcadas visible). crops/ son principalmente hojas exportables; los grupos con efectos de capa se escriben en group_effects.json y crops_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 en tree.json; no tener recorte no significa estado faltante.
  2. 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 en states respectivos. 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 como highlight de 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 en uncertain_hidden; solo escribe uncertain_hidden si 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 un effect_mode para esa parte (ver slicing.md "Efectos de grupo: horneado vs. motor"): baked (por defecto) — layer_id / select_ids usan el ID del grupo, el efecto está horneado en la imagen, el cuadro visible incluye el efecto, el cuadro lógico no; engine — select_ids usan las subcapas, los effect_params del grupo se copian en engine_effects, el motor los renderiza, la imagen no contiene píxeles de efecto. Cada parte así escribe una línea effect_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 con placeholder: true; los nombres/puntuaciones/números son texto dinámico) y la evidencia en reuse_candidates.json. Si se deben reutilizar, exporta una sola imagen y cada instancia escribe reuse_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 en reuse_decisions (evidencia, problema, imágenes de comparación, opciones) y deja que el usuario decida; por defecto, antes de decidir, exporta por separado. Nombra como mó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.
  3. Puerta de revisión: flatten + preview produce una vista previa anotada y un JSON (las etiquetas incluyen fx:baked / fx:engine, los efectos del motor dibujan un rango estimado para que el usuario pueda cambiar el modo durante la revisión; flatten enumerará en effect_issues las partes que perderán efectos). El usuario modifica el JSON y lo confirma; status permanece pending_review antes de la confirmación. preview omitirá los cuadros delimitadores invertidos o vacíos y dará una advertencia, sin interrumpir por ello.
  4. Exportar (.psjs): El script solo codifica una CONFIG_URL y lee las rutas del JSON del trabajo. Exporta PNG 1x por layer_id / select_ids: baked selecciona el grupo, el efecto se hornea en la imagen; engine selecciona las subcapas y las fusiona, la imagen no contiene efectos de grupo. Las instancias con reuse_of solo exportan una imagen compartida; las demás instancias solo registran sus límites. dynamic_text no genera imagen, solo exporta las propiedades del texto; art_text genera imagen.

Skills relacionados