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
.psjssur 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-toolsouag-psdpour une analyse hors ligne. Testé : lelayer_iddepsd-toolscorrespond aulayer.idd'UXP ; vous pouvez utiliser la structure hors ligne pour localiser, et ne confier à Photoshop que le rendu/l'exportation. Note : le bbox depsd-toolsn'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
DoJavaScriptde Windows /do javascriptvia AppleScript /evalScriptde CEP. JSX est en ES3, avec une API synchrone, et en mode maintenance. Ne considérez paspsx.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.psjssur 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
awaitde haut niveau. Les exemples officiels et les tests en dépendent ; n'écrivez pas uneasync function mainsans 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 }).commandNames'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, ouPlugins > Development > Record Action Commands...; n'inventez pas les noms de clés. dialogOptionss'écrit dans_optionsde 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 debatchPlaysans 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 metdialogOptionsdans_optionsdu descripteur, avec la valeur"silent".- Des paramètres
batchPlayinvalides provoquent un rejet ; des échecs d'exécution (cible inexistante) résolvent la promesse, et retournent{_obj:"error", message, result}.result === -128signifie 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/createSessionTokenfont partie de l'API FileSystemProvider officielle (voir section 4 pour les tests). require("uxp").scriptfournitexecutionContext,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 ouscript.argspour 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.argsest[]. 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.setResultpeut être appelé, retourneundefined, n'apparaît pas dans le code de sortie ou stdout dePhotoshop.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.
executionContextofficiel :isCancelled/onCancelpour 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é :isCancelledest un booléen ;reportProgresspeut être appelé, retourneundefined.suspendHistory({documentID, name})retourne{historySuspensionID},resumeHistory(id)regroupe les modifications suivantes en une seule étape, le nom apparaît dansdoc.historyStates. Les clés énumérables dehostControlpeuvent être vides ; utilisezObject.getOwnPropertyNames. Lisez l'historique avec le DOM (doc.historyStates/doc.activeHistoryState), n'utilisez pas batchPlaygethistoryStatesCount(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
.psben environ 18 secondes (dont environ 10 secondes pour ouvrir le fichier), et a écritexport_log.json. - Testé (Windows / PS 2026) : L'association de fichiers existe (
.psjs=Photoshop.PSJSFileType.200, ftype estPhotoshop.exe "%1").Start-Process script.psjsexécute effectivement le script et écrit le fichier de résultat. Il est toujours recommandé pour l'agent de passer explicitementPhotoshop.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 -aretourne 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.psjssans 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.documentssi un document a le mêmedoc.path; s'il est déjà ouvert, utilisez cette instance (n'en ouvrez pas un deuxième), sinon utilisezapp.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 desaveAs(..., 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.pathressemble àD:\work\file.psd. Les documents récupérés (ex : « xxx-récupéré ») peuvent avoir unpathvide etsaved === 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 aveccloseWithoutSaving()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 === falsed'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.suspendHistorypour 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 alorsdoc.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
- Le script exporte un PNG (et éventuellement un PSD).
- Côté agent, comparez avec une image de référence (CIEDE2000 ΔE, différence de pixels, zoom local).
- 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é.
- 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
gethistoryStatesCount. Cette dernière commande retourne « La commande "get" n'est actuellement pas disponible. » ; avecdontDisplay, une popup apparaît ; avecsilent, elle retourneresult: -25920. Utilisezdoc.historyStates/doc.activeHistoryState. -
setsur un document non actif échoue (« La commande "set" n'est actuellement pas disponible. »). Définissez d'abord la cible commeapp.activeDocumentavant d'utiliserset. La commandemakepour 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 utiliserframeFX). UtilisezgradientType: "shapeburst"pour les dégradés qui suivent le contour de la forme. -
innerShadowà clé unique peut être ignoré silencieusement ; écrivez plutôtinnerShadowMulti: [{ _obj: "innerShadow", ... }]. Après modification, utilisezgetpour lirelayerEffectset confirmez que la clé est bien présente. -
Chemins personnalisés : définissez d'abord
workPath, puis utilisezmake contentLayer. Les formes ainsi créées n'ont généralement paskeyOriginType; 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, utilisezmake contentLayeravecshape._obj = "rectangle"/"ellipse"et incluezunitValueQuadVersion: 1avec 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, pasgreen. Ne « corrigez » pas ce nom. -
executeAsModaldoit êtreawait. 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 uncatchvide 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 :
- UXP Scripting in Photoshop (
.psjs, 23.5, méthodes de lancement) - Quickstart
- How it works (await haut niveau, permissions des modules, FAQ : première version ne supporte pas le passage de paramètres, pas d'appel de script à script, pas de réseau)
- Scripting reference (
executionContext/hostControl) require("uxp").script(args,setResult)- executeAsModal
- batchPlay
- FileSystemProvider
- File access
- Samples
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) :
- 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ésvisible).crops/contient principalement les feuilles exportables ; les groupes avec effets de calque sont écrits dansgroup_effects.jsonetcrops_index.json(avec, si un composite est possible, une image recadrée du groupe), accompagnés deseffect_paramslus 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.jsonpour juger ; l'absence d'image recadrée n'est pas un état manquant. - 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 lesstatesrespectifs. 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 lahighlightde 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 dansuncertain_hidden. Écrivezuncertain_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 uneffect_modepour cette partie (voir slicing.md « Effets de groupe : cuire ou dessiner par le moteur ») :baked(par défaut) –layer_id/select_idsutilise 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_idsutilise les sous-calques, leseffect_paramsdu groupe sont copiés dansengine_effects, le moteur dessine l'effet, l'image ne contient pas les pixels d'effet. Chaque partie de ce type doit inclure une ligneeffect_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-lesplaceholder: true; les noms/scores/chiffres sont du texte dynamique) et des preuves dansreuse_candidates.json. Si la réutilisation est confirmée, exportez une seule image, chaque instance écritreuse_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 dansreuse_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èlemodule_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. - Point de contrôle de validation :
flatten+previewproduisent un aperçu annoté et un JSON (étiquettes avecfx: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 ;flattenliste danseffect_issuesles pièces qui perdraient des effets). L'utilisateur modifie le JSON et confirme ;statusrestepending_reviewavant la confirmation.previewignore les boîtes englobantes inversées ou vides et émet un avertissement, ne vous arrêtez pas pour cela. - Exportation (
.psjs) : Le script n'a qu'un seulCONFIG_URLcodé en dur, il lit les chemins depuis le JSON de la tâche. Exporte les PNG 1x parlayer_id/select_ids:bakedsélectionne le groupe, les effets sont cuits dans l'image ;enginesélectionne les sous-calques et les fusionne, l'image ne contient pas les effets du groupe. Les instances avecreuse_ofn'exportent qu'une seule image partagée, les autres instances n'enregistrent que leurs limites.dynamic_textne produit pas d'image, exporte uniquement les propriétés du texte ;art_textproduit une image.