CommunityImagegithub.com

younglark/photoshop-psjs

Utilisez cette compétence pour piloter Adobe Photoshop avec des scripts UXP autonomes (.psjs) : écrire, lancer, interroger et vérifier la création/édition/exportation de documents depuis un agent. Couvre executeAsModal, batchPlay, jetons de fichiers, sécurité des ID de documents, et différences entre psjs, plugins UXP et ExtendScript/JSX.

Qu'est-ce que photoshop-psjs ?

Cette compétence permet à un agent IA de contrôler Adobe Photoshop de manière automatisée et fiable en utilisant des scripts UXP autonomes (extension .psjs). Elle est conçue pour les tâches qui nécessitent absolument Photoshop, comme le rendu pixel par pixel avec les styles de calque, l'exportation de tranches par calque, ou l'utilisation de batchPlay pour créer des formes, du texte et des effets. La compétence fournit un cadre complet pour écrire, lancer et surveiller l'exécution des scripts, en gérant des aspects critiques tels que la sécurité des documents (ne modifier que le document cible), la gestion des erreurs (dialogueOptions 'silent'), et la création de fichiers de résultats JSON. Elle prend en charge Windows (PowerShell) et macOS (zsh), avec un processus de polling pour récupérer les résultats asynchrones. La compétence détaille également un flux de travail de découpage d'interface utilisateur pour les jeux, combinant l'analyse hors ligne avec psd-tools et l'exportation via .psjs, afin de produire des PNG 1x et un JSON de mise en page sémantique, en respectant des règles strictes de gestion des états, des effets de calque et de la réutilisation des ressources.

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

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Piloter Photoshop avec des scripts UXP (.psjs)

Recette exécutable pour les agents : créer, modifier et exporter des documents dans Photoshop. Les faits sont de deux types :

  • Officiels : issus de la documentation Adobe UXP, liens en fin de document.
  • Testés : expériences validées avec .psjs sur Windows et macOS, Adobe Photoshop 2026. Les éléments non vérifiés sont marqués comme non vérifié et ne doivent pas être considérés comme une API officielle.

Critère de succès : Le script écrit un JSON de résultat (contenant done / ok / fatal / errs) ; il ne modifie que le document cible spécifié par la tâche, sans affecter les autres documents ouverts ; si un alignement pixel parfait est requis, exporter en PNG et itérer après comparaison ΔE / différence de pixels avec une image de référence.

Arrêtez-vous d'abord : La tâche ne précise pas quel document modifier, ou elle demande d'écraser un document non enregistré par l'utilisateur, sans autorisation explicite.


1. Quand utiliser / Quand ne pas utiliser

Utilisez .psjs quand :

  • Vous avez besoin de Photoshop pour des opérations spécifiques : rendu de pixels avec styles de calque, exportation de tranches par calque, création de formes/texte/effets avec batchPlay, enregistrement des résultats en PSD/PNG.
  • Vous devez extraire une liste de tranches à partir d'un PSD/PSB, puis exporter des PNG 1x et un JSON de mise en page neutre pour le moteur (voir section 9).
  • L'agent doit exécuter une tâche en une seule fois (écrire le script → lancer → interroger les logs → récupérer les artefacts), sans nécessité de panneau persistant.

Ne lancez pas Photoshop quand :

  • Vous avez seulement besoin d'informations en lecture seule : arborescence des calques, noms, ID, texte, limites approximatives. Utilisez psd-tools ou ag-psd pour une analyse hors ligne. Testé : le layer_id de psd-tools correspond au layer.id d'UXP ; vous pouvez utiliser la structure hors ligne pour localiser, et ne confier à Photoshop que le rendu/l'exportation. Note : le bbox de psd-tools n'inclut pas les effets de calque ; les limites visuelles finales doivent être calculées dans Photoshop.

Utilisez un plugin UXP quand :

  • Vous avez besoin d'une connexion persistante et bidirectionnelle (ex : pont MCP, panneau, WebSocket). Officiel : les scripts n'ont pas de manifest / panneau ; Network, LaunchProcess, WebView, IPC sont indisponibles. Ces capacités nécessitent un plugin avec permissions déclarées dans le manifest.
  • Officiel : un plugin ne peut pas appeler un autre .psjs ; mais le code UXP d'un script peut généralement être déplacé dans un plugin.

Utilisez ExtendScript / JSX quand :

  • La cible est Photoshop 23.5 ou inférieur, ou vous ne pouvez utiliser que le COM DoJavaScript de Windows / do javascript via AppleScript / evalScript de CEP. JSX est en ES3, avec une API synchrone, et en mode maintenance. Ne considérez pas psx.jsx (la bibliothèque d'assistance ExtendScript de xbytor) comme un runtime.

2. Points officiels clés (à mémoriser d'abord)

  • Les scripts UXP autonomes sont disponibles depuis Photoshop 23.5, extension .psjs. Le débogage est possible avec UXP Developer Tool ≥ 1.6, mais l'exécution du script ne nécessite pas UDT.
  • Lancement officiel : Fichier > Scripts > Parcourir... ; glisser-déposer le .psjs sur l'icône du Dock (Mac) ou sur la zone de travail vide de Photoshop (Mac/Win) ; jouer via une action. Le double-clic pour ouvrir était marqué « à venir ».
  • Les scripts sont du JS moderne, supportant await de haut niveau. Les exemples officiels et les tests en dépendent ; n'écrivez pas une async function main sans l'appeler, puis quittez immédiatement.
  • Toute opération qui modifie le document ou l'état de l'application doit être encapsulée dans require("photoshop").core.executeAsModal(fn, { commandName }). commandName s'affiche dans la barre de progression (qui apparaît si le script dépasse environ 2-3 secondes, l'utilisateur peut annuler).
  • Quand le DOM est insuffisant, utilisez require("photoshop").action.batchPlay(descriptors, options). Les descripteurs sont en actionJSON. La documentation officielle recommande de privilégier le DOM. Pour obtenir les descripteurs, utilisez « Copier comme JavaScript » dans le panneau Actions en mode développeur, ou Plugins > Development > Record Action Commands... ; n'inventez pas les noms de clés.
  • dialogOptions s'écrit dans _options de chaque descripteur, avec les valeurs "silent" (par défaut, pas de popup même en cas d'erreur), "dontDisplay" (généralement pas de popup, mais peut en afficher en cas d'arguments manquants ou d'erreur), "display". Testé (PS 2026) : l'agent doit utiliser "silent". "dontDisplay" peut encore bloquer avec une boîte de dialogue d'erreur si la commande échoue (ex : La commande "get" n'est actuellement pas disponible.), le script attendra que l'utilisateur clique OK ; après quoi il retourne {_obj:"error", message:"", result:-128} (-128 est le code d'annulation officiel). "silent" ne bloque pas, retourne environ 1–5ms plus tard {_obj:"error", message:"Nom du script : La commande "…" n'est actuellement pas disponible.", result:-25920}. A déjà été testé en passant { dialogOptions: "dontDisplay" } comme second paramètre de batchPlay sans erreur, mais le tableau des options officielles n'a pas cette clé, et il est dangereux d'utiliser "display" pour vérifier son effet. Le nouveau code met dialogOptions dans _options du descripteur, avec la valeur "silent".
  • Des paramètres batchPlay invalides provoquent un rejet ; des échecs d'exécution (cible inexistante) résolvent la promesse, et retournent {_obj:"error", message, result}. result === -128 signifie que l'utilisateur a annulé. Vérifiez toujours le tableau retourné.
  • Système de fichiers : les scripts n'ont pas de manifest, les permissions sont intégrées à Photoshop. La documentation officielle mentionne toujours : vous pouvez utiliser les sélecteurs de fichiers et getTemporaryFolder(). getEntryWithUrl / createSessionToken font partie de l'API FileSystemProvider officielle (voir section 4 pour les tests).
  • require("uxp").script fournit executionContext, args, setResult(result). La FAQ officielle (notes de la première version) indiquait : la première version ne supporte pas le passage d'arguments aux scripts. Ne comptez pas sur les arguments de la ligne de commande ou script.args pour passer la configuration de la tâche ; écrivez les chemins et paramètres dans le script, ou faites lire au script un JSON voisin. Testé (Windows / PS 2026, Photoshop.exe script.psjs) : script.args est []. Si vous ajoutez des paramètres CLI supplémentaires après le chemin du script, le script ne s'exécute pas (aucun fichier de résultat en 3 minutes), le lanceur revient immédiatement avec code de sortie 0, stdout sans sortie de script. Ne passez pas de paramètres CLI supplémentaires. setResult peut être appelé, retourne undefined, n'apparaît pas dans le code de sortie ou stdout de Photoshop.exe. Utilisez toujours un fichier de résultat.
  • Un seul script peut s'exécuter à la fois, et un script ne peut pas en appeler un autre.
  • executionContext officiel : isCancelled / onCancel pour répondre à l'annulation, reportProgress({ value, commandName }) pour mettre à jour la barre de progression, hostControl.suspendHistory({ documentID, name }) + resumeHistory(id, commit) pour regrouper un lot de modifications en une seule étape d'historique, facilitant l'annulation pour l'artiste. Testé : isCancelled est un booléen ; reportProgress peut être appelé, retourne undefined. suspendHistory({documentID, name}) retourne {historySuspensionID}, resumeHistory(id) regroupe les modifications suivantes en une seule étape, le nom apparaît dans doc.historyStates. Les clés énumérables de hostControl peuvent être vides ; utilisez Object.getOwnPropertyNames. Lisez l'historique avec le DOM (doc.historyStates / doc.activeHistoryState), n'utilisez pas batchPlay get historyStatesCount (cette commande n'est pas disponible, voir section 7).

3. Lancement et interrogation par l'agent (testé sous Windows)

La documentation officielle ne décrit pas officiellement le passage d'un .psjs à Photoshop.exe en ligne de commande. Testé (Windows / Photoshop 2026) :

& "C:\Program Files\Adobe\Adobe Photoshop 2026\Photoshop.exe" "D:\work\ps-job\run_job.psjs"
  • Pas besoin de Creative Cloud Desktop, d'UDT ou du mode développeur.
  • Si Photoshop est déjà ouvert, le script s'exécute dans l'instance existante.
  • Le lanceur revient immédiatement, le script continue de manière asynchrone dans PS. Vous devez interroger (polling) le JSON de résultat écrit par le script lui-même (contenant idéalement done, ok, fatal, errs), ne vous fiez pas au code de sortie du processus.
  • Testé : un script d'exportation a exporté 28 tranches depuis un .psb en environ 18 secondes (dont environ 10 secondes pour ouvrir le fichier), et a écrit export_log.json.
  • Testé (Windows / PS 2026) : L'association de fichiers existe (.psjs=Photoshop.PSJSFileType.200, ftype est Photoshop.exe "%1"). Start-Process script.psjs exécute effectivement le script et écrit le fichier de résultat. Il est toujours recommandé pour l'agent de passer explicitement Photoshop.exe + le chemin du script, et de se fier au fichier de résultat.
  • Avant de lancer, assurez-vous que PS n'a pas de boîte de dialogue modale ouverte (invite de récupération après crash, boîte de sauvegarde, etc.). Si une boîte de dialogue est ouverte, le script ne s'exécutera pas comme prévu et l'interrogation expirera ; en cas de timeout, faites d'abord une capture d'écran de l'interface PS, ne relancez pas aveuglément.

Flux de travail pour agent distant : Écrire le .psjs côté agent → copier vers la machine avec Photoshop (uniquement dans les répertoires autorisés par l'utilisateur) → lancer via shell et interroger les logs → copier les PNG/PSD/logs en retour → effectuer une comparaison pixel par pixel si nécessaire.

Exemple d'interrogation (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 (testé, Photoshop 2026, Mac mini) : La documentation officielle ne mentionne que le glisser-déposer sur le Dock / la fenêtre. Le lancement en ligne de commande ci-dessous n'est pas documenté officiellement mais a été testé et fonctionne :

open -a "Adobe Photoshop 2026" /path/to/run_job.psjs
# Alternative si .psjs est associé : open /path/to/run_job.psjs
  • Démarrage à froid : PS n'est pas en cours d'exécution. open -a retourne en environ 0,3 seconde (exit 0). PS démarre et exécute le script automatiquement, le fichier de résultat est écrit en environ 8 secondes.
  • Démarrage à chaud : PS est déjà en cours d'exécution. Le script s'exécute dans l'instance existante et écrit le résultat en quelques secondes.
  • L'utilisation de open xxx.psjs sans l'option -a, via l'association de fichiers, exécute également le script.
  • getEntryWithUrl("file:/Users/<utilisateur>/...") permet d'écrire des fichiers sans sélecteur.
  • Comme sous Windows : le lanceur revient immédiatement, vous devez interroger le fichier de résultat, n'ajoutez pas de paramètres CLI supplémentaires.

Exemple d'interrogation (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"

Un squelette de script se trouve dans examples/run_job.psjs (await de haut niveau, executeAsModal, garde des ID de document, fichier de résultat, try/catch). Testé : en suivant ce squelette, le script fonctionne : écrit done/ok, exporte preview.png, ferme les documents qu'il a créés, et l'ensemble des ID des autres documents ouverts reste inchangé.


4. Accès aux fichiers

FileSystemProvider officiel : getFileForOpening / getFileForSaving / getFolder, getTemporaryFolder, getEntryWithUrl(url), createEntryWithUrl, createSessionToken(entry).

Le _path passé à batchPlay doit être un jeton de session (session token), pas un chemin système brut. Documentation officielle : lors de l'utilisation du DOM de Photoshop (ex : app.open(file), doc.saveAs.psd(file, …)), vous pouvez passer directement une entrée File/Folder, l'hôte convertira automatiquement en jeton.

Testé (script PS 2026, sans sélecteur) :

const fs = require("uxp").storage.localFileSystem;
const root = await fs.getEntryWithUrl("file:/D:/work/ps-job"); // le dossier doit exister
const out = await root.createFile("job_log.json", { overwrite: true });
await out.write(JSON.stringify(log, null, 2));

Les URL de type file:/D:/... fonctionnent sous Windows. La documentation des scripts ne garantit toujours que le sélecteur + le répertoire temporaire. Considérez l'écriture dans « un chemin arbitraire sans sélecteur » comme un comportement testé sur PS 2026 ; si vous changez de version, faites d'abord un test d'écriture. N'appelez pas de modules réseau – l'environnement de script officiel les interdit.


5. Périmètre et sécurité des documents (obligatoire)

Principe : le script ne modifie que le document cible spécifié par la tâche. La cible peut être un document créé par le script, ou un PSD existant nommé par la tâche (l'itération sur des designs existants est un cas courant). Les autres documents ouverts ne doivent être ni modifiés, ni enregistrés, ni fermés.

Définir l'ensemble cible targets :

  • Nouveau document : l'ID retourné par app.createDocument() est ajouté à targets.
  • Itération sur un PSD existant : localisez-le via le chemin donné par la tâche. Vérifiez d'abord dans app.documents si un document a le même doc.path ; s'il est déjà ouvert, utilisez cette instance (n'en ouvrez pas un deuxième), sinon utilisez app.open(entry) pour l'ouvrir. Se fier uniquement au nom n'est pas fiable (homonymes, copies « -récupéré »). Privilégiez le chemin, puis l'ID de document donné par la tâche. Testé : utiliser le chemin permet de réutiliser la même instance (même ID de document, pas de deuxième ouverture) ; après une modification non enregistrée, doc.saved === false ; lors de l'utilisation de saveAs(..., true) pour enregistrer une nouvelle version, le mtime et la taille du fichier d'origine restent inchangés, le document reste ouvert et pointe toujours vers le chemin d'origine. Sous Windows, doc.path ressemble à D:\work\file.psd. Les documents récupérés (ex : « xxx-récupéré ») peuvent avoir un path vide et saved === false ; on ne peut pas les trouver par le chemin, utilisez l'ID donné par la tâche.
  • Les documents temporaires (ex : tranches créées par « Nouveau calque ») sont ajoutés à targets, et fermés avec closeWithoutSaving() une fois utilisés.

Garde : Avant chaque batchPlay, enregistrement ou fermeture, vérifiez que app.activeDocument.id est dans targets. Cette vérification ne couvre que les descripteurs qui ciblent implicitement le document actif ; pour les descripteurs qui contiennent explicitement { _ref: "document", _id }, vérifiez aussi cet ID. Avant et après l'exécution, enregistrez dans le log app.documents.map(d => ({ name: d.name, id: d.id, path: d.path })). Testé : Lors de l'utilisation de make sur un calque avec un { _ref: "document", _id } d'un document non actif, le calque est créé sur ce document et activeDocument ne change pas. Il est donc impératif de vérifier les ID explicites. Cependant, set n'est pas disponible pour les documents non actifs (voir section 7) ; pour modifier une propriété, définissez d'abord app.activeDocument = target, puis utilisez set.

Lors de la modification d'un document existant :

  • Si le document cible est déjà ouvert et a des modifications non enregistrées (doc.saved === false d'après la doc officielle), cela signifie que l'utilisateur le modifie manuellement. Par défaut, vous pouvez continuer à éditer (c'est le but de l'itération), mais n'enregistrez pas par-dessus, sauf si la tâche le demande explicitement ; notez d'abord dans le log qu'il était en état « sale » avant l'exécution.
  • Utilisez hostControl.suspendHistory pour regrouper les modifications du script en une seule étape d'historique, permettant à l'utilisateur d'annuler en un seul Ctrl+Z.
  • La stratégie de sauvegarde dépend de la tâche : par défaut, enregistrez une nouvelle version (ex : xxx_v14.psd), conservez le fichier original ; si la tâche demande explicitement une « mise à jour sur place », utilisez alors doc.save().
  • À la fin du script, ne fermez pas les documents cibles que l'utilisateur avait déjà ouverts. Fermez uniquement les documents que le script a lui-même ouverts ou créés et que la tâche n'exige pas de conserver.

Nettoyage automatique : executionContext.hostControl.registerAutoCloseDocument(docID) permet de fermer automatiquement les documents temporaires en cas d'annulation ou de fin de modal ; à utiliser uniquement pour les documents créés par le script. Si l'artiste doit continuer à modifier, appelez d'abord unregisterAutoCloseDocument. N'utilisez pas cette fonction sur les documents existants de l'utilisateur.


6. Boucle de vérification

  1. Le script exporte un PNG (et éventuellement un PSD).
  2. Côté agent, comparez avec une image de référence (CIEDE2000 ΔE, différence de pixels, zoom local).
  3. En fonction des différences, modifiez le script (chemins, dégradés, styles de calque). Ne modifiez pas directement le document utilisateur ouvert en espérant une reproductibilité.
  4. Relancez, exportez à nouveau, comparez jusqu'à atteindre le seuil ou expliquez l'écart restant.

7. Pièges testés

  • dialogOptions: "dontDisplay" peut encore bloquer avec une boîte de dialogue d'erreur en cas d'échec. Chaque descripteur exécuté par l'agent doit inclure _options: { dialogOptions: "silent" }. En cas de timeout de l'interrogation, vérifiez d'abord si PS a affiché une boîte d'erreur ; ne relancez pas aveuglément. Ne lancez pas le script suivant si une boîte de dialogue est ouverte.

  • Lisez l'historique avec le DOM, n'utilisez pas batchPlay get historyStatesCount. Cette dernière commande retourne « La commande "get" n'est actuellement pas disponible. » ; avec dontDisplay, une popup apparaît ; avec silent, elle retourne result: -25920. Utilisez doc.historyStates / doc.activeHistoryState.

  • set sur un document non actif échoue (« La commande "set" n'est actuellement pas disponible. »). Définissez d'abord la cible comme app.activeDocument avant d'utiliser set. La commande make pour les calques peut fonctionner sur un document non actif sans changer le document actif – l'ID du document dans le descripteur doit être inclus dans la garde.

  • Les contours multiples nécessitent frameFXMulti (une seule peut utiliser frameFX). Utilisez gradientType: "shapeburst" pour les dégradés qui suivent le contour de la forme.

  • innerShadow à clé unique peut être ignoré silencieusement ; écrivez plutôt innerShadowMulti: [{ _obj: "innerShadow", ... }]. Après modification, utilisez get pour lire layerEffects et confirmez que la clé est bien présente.

  • Chemins personnalisés : définissez d'abord workPath, puis utilisez make contentLayer. Les formes ainsi créées n'ont généralement pas keyOriginType ; ce ne sont pas des formes dynamiques dont les coins peuvent être arrondis dans la barre de propriétés. Pour des coins arrondis modifiables, utilisez make contentLayer avec shape._obj = "rectangle" / "ellipse" et incluez unitValueQuadVersion: 1 avec les quatre rayons de coin.

  • Les polices sont assignées par leur nom PostScript (ex : textItem.characterStyle.font = "MuseoSansRounded-1000") et doivent être installées ; installez-les pour l'utilisateur, il n'est pas nécessaire de les installer au niveau machine.

  • Le champ vert dans les descripteurs RGB s'appelle grain, pas green. Ne « corrigez » pas ce nom.

  • executeAsModal doit être await. Si vous oubliez, le code suivant s'exécutera avant que le modal ne soit actif.

  • L'annulation par l'utilisateur provoque une exception dans batchPlay ; ne faites pas un catch vide qui avalerait l'annulation, sinon le script ne s'arrêtera pas.

Les actionJSON pour les styles de calque et les formes se trouvent dans references/batchplay.md.


8. Sources

Officielles :

Les compléments testés proviennent de l'expérience de création de composants d'interface utilisateur par lots avec .psjs et de la comparaison pixel par pixel avec une image de référence ; ils ne font pas partie de la norme Adobe.


9. Flux de travail de découpage pour agent

Découpez une interface en PNG 1x importables par un moteur de jeu, et produisez un JSON de mise en page intermédiaire, sémantique par composant et indépendant du moteur. Les détails, schéma, conventions de nommage, méthodes d'identification et résultats de test sont dans references/slicing.md. Suivez d'abord l'arbre de décision au début de ce document : Ouvrez le matériel (incluant les effets de calque sur les groupes, et choisissez un effect_mode pour chaque pièce affectée) → Identifiez les composants → Distinguez les pièces partagées de celles qui varient selon l'état → Distinguez les variantes des anciennes versions → Marquez comme « missing » uniquement les pièces qui varient → Déterminez si les éléments répétés sont réutilisés → Arrêtez-vous au point de contrôle. Scripts et assistants Python : examples/export_slices.psjs, examples/slicing_helper.py, examples/naming_rules.example.json, examples/export_config.example.json.

Environnement Python : Exécutez l'assistant dans le venv du projet, n'installez pas les paquets dans le Python système. Nécessite psd-tools[composite], Pillow, numpy. Pour ouvrir de grands documents, utilisez l'appel vérifié PSDImage.open(path, parse_limits=ParseLimits(max_objects=None)) (ne devinez pas les paramètres, ne définissez pas l'attribut de classe ParseLimits.max_objects). Voir « Environnement Python » dans slicing.md.

Répartition des tâches : L'assistant prépare uniquement le matériel (image complète de l'état par défaut, recadrages couche par couche avec ID, arborescence des calques incluant les calques masqués, candidats pour le 9 points (nine-slice)). L'agent qui exécute cette compétence lit ce matériel et rédige le manifest : composants, parties, noms standardisés, types, états et hiérarchie. --rules est une convention de nommage optionnelle pour le projet. La commande infer peut encore produire un brouillon de mots-clés (draft_manifest.json), mais cela ne remplace pas la liste de l'agent.

Flux (pas d'exportation avant confirmation) :

  1. Préparer le matériel (hors ligne) : prepare. --artboard <nom ou id de la planche> est optionnel ; si omis, traite toutes les planches visibles de premier niveau ; s'il n'y a pas de planche, traite la toile entière. L'arborescence inclut les calques masqués (marqués visible). crops/ contient principalement les feuilles exportables ; les groupes avec effets de calque sont écrits dans group_effects.json et crops_index.json (avec, si un composite est possible, une image recadrée du groupe), accompagnés des effect_params lus par psd-tools (type, mode de fusion, couleur, opacité, angle, distance, taille, extension/obstruction, position du contour). Utilisez l'index pour trouver l'ID, ne devinez pas le nom du fichier. Si un groupe d'ID n'a pas d'image recadrée, n'utilisez pas directement une feuille interne – vérifiez d'abord si ce groupe a des effets. Pour les groupes sans effet, les calques vides ou ceux en dehors de la planche, revenez à tree.json pour juger ; l'absence d'image recadrée n'est pas un état manquant.
  2. L'agent rédige le manifest : Identifiez les composants interactifs (groupes d'onglets, barre inférieure, boutons, lignes de liste, etc.). Séparez les états (fond, surbrillance, icône, texte) en parties distinctes ; ne cuisez pas les états ensemble. Regardez d'abord quelles parties sont partagées entre les états et lesquelles changent : les parties partagées vont dans shared (le nom de fichier n'a pas de suffixe d'état), les parties qui changent vont dans les states respectifs. Un calque masqué n'est considéré comme un état alternatif que si le sujet/contenu du composant est le même et que la différence réside uniquement dans le style de l'état (luminosité, contour, lueur, palette de couleurs, etc.). Si le même emplacement contient un contenu ou un badge différent, considérez-le comme une ancienne version et ignorez-le. Ne l'utilisez pas pour remplacer une ressource partagée réelle, et ne marquez pas la partie partagée comme « missing ». Un calque masqué qui se trouve dans l'emplacement de l'élément actuellement sélectionné, avec le même sujet et uniquement un style de lueur/surbrillance, doit être traité comme la highlight de cet état (l'état sélectionné par défaut doit également être inclus). Un calque de lueur/bulle superposé à un fond sélectionné visible, même avec une forme différente, est une surbrillance superposée, pas un remplacement ; ne le mettez pas dans uncertain_hidden. Écrivez uncertain_hidden (avec les deux images recadrées) uniquement si le contenu ou le thème ne correspond pas. Pour les éléments « missing », utilisez comme modèle l'élément le plus complet du même groupe (ex : l'élément sélectionné a base + highlight + label). Listez tous les éléments frères qui manquent d'au moins un de ces composants, y compris highlight. Une ligne de liste avec un style spécial unique n'est qu'une instance de cette ligne ; n'inférez pas d'états manquants pour les autres lignes, et n'inférez pas un état normal manquant pour cette ligne, sauf si le design contient des variantes complètes pour chaque ligne. Lors du choix de la cible d'exportation, vérifiez si le groupe parent le plus proche de l'élément (ou le groupe représentant l'élément) a un effet de calque (ex : ombre portée). Si l'effet est sur le groupe mais pas sur les feuilles internes, choisissez un effect_mode pour cette partie (voir slicing.md « Effets de groupe : cuire ou dessiner par le moteur ») : baked (par défaut) – layer_id / select_ids utilise l'ID du groupe, l'effet est cuit dans l'image, la boîte visible inclut l'effet, la boîte logique ne l'inclut pas ; engine – select_ids utilise les sous-calques, les effect_params du groupe sont copiés dans engine_effects, le moteur dessine l'effet, l'image ne contient pas les pixels d'effet. Chaque partie de ce type doit inclure une ligne effect_reason. Si les règles du projet ou l'utilisateur spécifient une méthode, suivez-la. La seule chose interdite est de sélectionner uniquement les sous-calques sans enregistrer les effets (les effets sont alors perdus silencieusement). Interdiction d'inventer. Pour les éléments répétés, déterminez d'abord s'ils sont réutilisés en fonction de leur usage dans l'interface utilisateur, du bon sens de l'UI de jeu (les lignes de liste, les cadres d'avatar, les boutons similaires, les médailles de classement, les icônes de monnaie, les barres de progression sont généralement réutilisés ; les images d'avatar sont du contenu dynamique, séparez-les du cadre et marquez-les placeholder: true ; les noms/scores/chiffres sont du texte dynamique) et des preuves dans reuse_candidates.json. Si la réutilisation est confirmée, exportez une seule image, chaque instance écrit reuse_of: <nom_partagé> (le nom partagé n'a pas de numéro d'instance). Si cela ne correspond pas à l'image d'effet, suspectez d'abord une erreur de jugement, ne séparez que les instances incohérentes. Si les preuves logiques sont solides mais ne correspondent pas, ou si l'avatar et le cadre sont combinés dans le PSD, écrivez dans reuse_decisions (preuves, problème, images de comparaison, options) et laissez l'utilisateur décider. Par défaut, avant la décision, exportez séparément. Nommez selon le modèle module_type_usage_etat (en minuscules ; pour les parties partagées, omettez la partie état). N'utilisez pas directement le nom du calque PSD. Types : image | nine_slice | dynamic_text | art_text.
  3. Point de contrôle de validation : flatten + preview produisent un aperçu annoté et un JSON (étiquettes avec fx:baked / fx:engine, les effets moteur dessinent une estimation de la zone pour faciliter la modification du mode par l'utilisateur lors de la validation ; flatten liste dans effect_issues les pièces qui perdraient des effets). L'utilisateur modifie le JSON et confirme ; status reste pending_review avant la confirmation. preview ignore les boîtes englobantes inversées ou vides et émet un avertissement, ne vous arrêtez pas pour cela.
  4. Exportation (.psjs) : Le script n'a qu'un seul CONFIG_URL codé en dur, il lit les chemins depuis le JSON de la tâche. Exporte les PNG 1x par layer_id / select_ids : baked sélectionne le groupe, les effets sont cuits dans l'image ; engine sélectionne les sous-calques et les fusionne, l'image ne contient pas les effets du groupe. Les instances avec reuse_of n'exportent qu'une seule image partagée, les autres instances n'enregistrent que leurs limites. dynamic_text ne produit pas d'image, exporte uniquement les propriétés du texte ; art_text produit une image.

Skills associés