Communitygithub.com

Pipeline d'animation de sprites

Importez des feuilles de sprites existantes ou des images ordonnées et corrigez le découpage, les références d'atlas, les pivots ou le timing dans Godot 4, Unity 6 ou Phaser 3 ; ne génère pas d'art ni de squelettes.

Qu'est-ce que Pipeline d'animation de sprites ?

Ce skill permet d'importer et de corriger des animations de sprites dans les moteurs Godot 4, Unity 6 et Phaser 3 à partir de feuilles de sprites ou d'images ordonnées existantes. Il se concentre sur l'ajustement du timing d'animation, les références d'atlas, les pivots et le découpage, sans générer de nouveaux assets artistiques. Le workflow s'appuie sur des commandes CLI comme `pixo asset slice`, `pixo asset pack`, `pixo asset frames check` et `pixo asset frames align`, et intègre les animations via l'API native de chaque moteur (SpriteFrames pour Godot, animations pour Phaser, Animation Clip et Animator pour Unity). Il détecte et corrige les problèmes courants comme le 'wobble' des pieds, le glissement latéral ou les différences de taille entre frames, et assure une vérification complète avec `pixo game verify`. Les conventions de projet, les versions installées et les choix explicites de l'utilisateur sont prioritaires.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/OpenPixo/OpenPixo/tree/HEAD/skills/sprite-animation-pipeline

Demander à votre IA préférée

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

Documentation

Que fait Pipeline d'animation de sprites ?

Importez des images ordonnées ou des feuilles de sprites dans Godot 4, Unity 6 ou Phaser 3. Corrigez le timing d'animation, les références d'atlas et les pivots. Les conventions de projet, les versions installées, l'architecture, le style artistique et les choix explicites de l'utilisateur sont prioritaires. Conservez une feuille et un format fonctionnels lorsque la tâche ne change que le timing ; le découpage et le réempaquetage sont facultatifs. Ce workflow utilise des assets existants plutôt que de générer de nouvelles animations ; les nouvelles images proviennent de pixo media generate --sheet <C>x<R> --frames (la section média du prompt), qui les écrit déjà sur une seule toile.

Chemin rapide

  1. Inspectez la feuille ou les images sélectionnées avec pixo asset info <chemin> --json ; lisez les définitions des clips actuels.
  2. Confirmez la taille et l'ordre des cellules, les plages de clips, la ligne de base, le pivot et le timing pour les boucles ou les plans uniques. pixo asset frames check <images...> --json mesure la ligne de base et la dérive pour vous.
  3. Choisissez la branche directe-feuille ou empaquetage ci-dessous ; lisez les chemins de sortie réels de l'opération.
  4. Intégrez via le propriétaire d'animation existant du moteur sans déplacer la collision de gameplay.
  5. Exécutez pixo game verify --steps check,build,run --screenshot --json, inspectez les journaux et les images, puis regardez une boucle complète et un plan unique de manière interactive.

Les commandes supposent PIXO_PROJECT_ID ; sinon ajoutez --project <id>. Les chemins et les nombres d'images ci-dessous sont des exemples ; les feuilles sans métadonnées n'identifient pas leurs propres clips. Unity n'a pas d'étape run ni de capture d'écran ici : utilisez --steps check,build et regardez les clips dans l'Éditeur.

Choisissez le plus petit changement de format

Entrée ou demandeChoisissezPréservez
Feuille régulière fonctionnelle, changement de timing uniquementSpriteFrames existant, clip Unity ou feuille PhaserPlages d'images, clé de texture, ligne de base partagée
Grille régulière nécessitant des images séparéespixo asset slice --cell LxH ou --grid CxR avec un chemin d'entréeMarge, espacement et couverture attendue
Les images vacillent, glissent ou diffèrent en taillepixo asset frames check, puis frames alignOrdre d'entrée, une échelle pour chaque image
PNG ordonnés pour Godotpack --format godot-tresOrdre d'entrée ; gardez PNG et TRES ensemble
PNG ordonnés pour Phaserpack --format texturepacker-jsonOrdre d'entrée, clés de descripteur réelles
Feuille ou images pour UnityImporter en tant que Sprite et découper dans Unity ; pack n'a pas de sortie UnityPivot, Pixels Par Unité, .meta existant
Images rognées avec pivots personnalisésPipeline existant avec métadonnéesDécalages de rognage et pivots ; l'empaquetage d'images seules ne peut pas les récupérer

Enregistrez uniquement les champs de contrat pertinents : taille de la toile et des cellules, ordre ligne par ligne, plages de clips, FPS, durées d'image, boucle et ligne de base pour les pieds. Des toiles de taille égale avec un ancrage partagé évitent le vacillement d'image à image ; les limites opaques ne sont pas le pivot.

Découpage et empaquetage d'ancrages

pixo asset slice public/assets/player.png --cell 32x32 --out derived/player-frames --dry-run --json
pixo asset slice public/assets/player.png --cell 32x32 --out derived/player-frames --json
pixo asset pack sprites/run/frame-0000.png sprites/run/frame-0001.png --format godot-tres --padding 1 --out derived/run-godot --json
pixo asset pack public/sprites/run/frame-0000.png public/sprites/run/frame-0001.png --format texturepacker-json --padding 1 --out public/atlases/run --json

Utilisez les chemins PNG retournés par le rapport de découpage ; les commandes d'empaquetage à deux images n'illustrent que l'ordre. --grid nécessite une division exacte après la marge et l'espacement ; --cell peut laisser des cellules de bordure incomplètes inutilisées. Vérifiez la couverture complète et le nombre d'images. Excluez délibérément les cellules vides et les images d'autres clips. Lisez results, extraOutputs, reportPath, les échecs et originalsPreserved ; les destinations existantes sont ignorées.

Faits sur l'empaquetage :

  • Le nom de base dérive de la première entrée et conserve ses répertoires relatifs sous --out ; lisez les chemins plutôt que de deviner.
  • Les sorties sont <stem>.atlas.png plus .atlas.tres ou .atlas.json.
  • L'empaquetage peut réorganiser le placement spatial mais les descripteurs préservent l'ordre d'entrée.
  • Aucune rotation, rognage, extrusion de bord, nommage de clip ou pivot personnalisé n'est généré.
  • Le remplissage est une séparation transparente, pas des pixels de bord dupliqués.

Vérifier et aligner les images

pixo asset frames check public/assets/hero/hero-run-1.png public/assets/hero/hero-run-2.png public/assets/hero/hero-run-3.png --json
pixo asset frames align public/assets/hero/hero-run-*.png --canvas 64x64 --padding 1 --out derived/hero-run --json

Passez les images dans l'ordre de jeu (un glob shell trie -10 avant -2 ; listez-les lorsqu'il y en a dix ou plus). frames check n'écrit aucune image. Par image, results[].detail a les bounds dessinés, bottomGap (rangées sous les pieds), feetX (centre des rangées les plus basses, qu'une arme balancée ne déplace pas), empty et touchesEdge. summary juge l'ensemble : baselineSpreadPx (balancement des pieds), feetXSpreadPx (glissement), heightDriftPercent, emptyFrames, edgeFrames et une phrase simple par problème dans issues ; ok est vrai quand il n'y en a pas. Une position accroupie, un écrasement ou un saut change la hauteur intentionnellement ; la même pose à différentes hauteurs est une dérive du modèle.

frames align écrit chaque image dans <out>/<chemin d'entrée>.png sur une seule toile : les pieds sur une ligne padding au-dessus du bas, feetX sur la ligne centrale, une échelle pour toutes afin qu'une position accroupie reste plus courte qu'une position debout. --canvas LxH met à l'échelle chaque image par le même facteur pour l'adapter ; sans cela, la toile est la plus petite qui les contient tous. --match-height met d'abord à l'échelle chaque dessin à la hauteur médiane, pour la dérive uniquement. --filter nearest garde le pixel art net. Son summary revérifie les images alignées. Les sorties existantes sont ignorées, comme pour chaque opération sur les assets.

Godot 4 : timing SpriteFrames

godot-tres émet SpriteFrames format=3 avec un clip default en boucle à 5 FPS. Gardez PNG et TRES ensemble ; la référence de texture est relative. Importez les nouvelles images via pixo game verify --steps check --json.

Après avoir substitué le chemin rapporté, cela adapte un clip réel de quatre images :

func configure_run(sprite: AnimatedSprite2D) -> void:
    var packed := load("res://sprites/run/run.atlas.tres") as SpriteFrames
    if packed == null or packed.get_frame_count(&"default") != 4:
        push_error("Expected four run frames")
        return
    var frames := packed.duplicate() as SpriteFrames
    frames.rename_animation(&"default", &"run")
    frames.set_animation_speed(&"run", 10.0)
    frames.set_animation_loop(&"run", true)
    frames.set_frame(&"run", 0, frames.get_frame_texture(&"run", 0), 2.0)
    sprite.sprite_frames = frames
    sprite.centered = true
    sprite.offset = Vector2(0, -16) # Exemple : ancre bas-centre sur une toile de 32px.
    sprite.play(&"run")

La durée d'image 2.0 signifie deux fois la durée d'image normale, pas deux secondes. Utilisez la ligne de base convenue pour le décalage ; gardez CharacterBody2D et CollisionShape2D stables. Les clips à plan unique nécessitent loop=false ; connectez animation_finished une seule fois et verrouillez la transition par l'animation active. Référence : Godot 4.3 SpriteFrames.

Phaser 3 : timing de feuille ou d'atlas

// preload(), pour une feuille réelle de 32px :
this.load.spritesheet('player', 'assets/player.png', { frameWidth: 32, frameHeight: 32 });
// create(), avec la plage de course réelle du projet :
if (!this.anims.exists('player-run')) {
  this.anims.create({ key: 'player-run',
    frames: this.anims.generateFrameNumbers('player', { start: 2, end: 5 }),
    frameRate: 10, repeat: -1 });
}
player.setOrigin(0.5, 1).play('player-run', true);

Les assets publics Vite se chargent sans public/ dans l'URL. Pour les atlas, this.load.atlas(key, pngUrl, jsonUrl) charge la paire retournée. Les clés de hachage TexturePacker sont les chemins relatifs au projet d'entrée ; lisez-les ou getFrameNames(). Utilisez une liste ordonnée explicite lorsque les noms n'encodent pas l'ordre.

// orderedNames provient de la liste de descripteurs/clips examinée.
this.anims.create({ key: 'hero-run', frameRate: 10, repeat: -1,
  frames: orderedNames.map((frame, index) => ({
    key: 'hero-atlas', frame, duration: index === 0 ? 100 : 0,
  })),
}); // À 10 FPS, 100 ms supplémentaires maintiennent la première image pour 200 ms au total.

Protégez la création d'animations globales avec this.anims.exists comme ci-dessus ; les clés survivent aux redémarrages de Scène. repeat: 0 joue une seule fois ; utilisez un écouteur de fin de plan unique dédié. Changer l'origine affecte le placement du corps ; inspectez la taille et le décalage plutôt que de déplacer la collision pour masquer un mauvais pivot. Référence : Phaser 3.90 types d'animation.

Unity 6 : importateur, clip et Animator

Unity ne lit ni godot-tres ni le JSON de TexturePacker sans un package supplémentaire. Placez la feuille sous Assets/, puis définissez Texture Type Sprite, Sprite Mode Multiple et les Pixels Per Unit réels. Pour le pixel art, ajoutez le filtre Point et pas de compression. Découpez par taille de cellule dans l'éditeur de sprite, avec un pivot partagé comme Bottom. Le découpage scripté passe par ISpriteEditorDataProvider depuis SpriteDataProviderFactories ; TextureImporter.spritesheet est l'ancien chemin. com.unity.2d.aseprite importe les fichiers .aseprite directement, avec les clips, lorsque l'art commence là.

Les clips peuvent être créés en sélectionnant des sprites et en les déposant dans la fenêtre d'animation, ou depuis un script lorsqu'il y en a beaucoup. Cet exemple uniquement pour l'Éditeur construit un clip en boucle de quatre images et maintient la première image :

using System;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public static class HeroClips
{
    [MenuItem("Tools/Create Hero Run Clip")]
    public static void CreateRun()
    {
        const float frame = 0.1f; // 10 FPS.
        // LoadAllAssetsAtPath n'a pas d'ordre promis, et hero_10 se trie avant hero_2 en tant que texte.
        var sprites = AssetDatabase.LoadAllAssetsAtPath("Assets/Art/hero.png").OfType<Sprite>()
            .OrderBy(sprite => int.Parse(Regex.Match(sprite.name, @"\d+$").Value))
            .Skip(2).Take(4).ToArray();
        if (sprites.Length != 4) throw new InvalidOperationException("Expected four run frames");
        var keys = sprites.Select((sprite, index) => new ObjectReferenceKeyframe {
            time = index == 0 ? 0f : (index + 1) * frame, value = sprite,
        }).ToArray();
        var clip = new AnimationClip { frameRate = 1f / frame };
        AnimationUtility.SetObjectReferenceCurve(clip,
            EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite"), keys);
        var settings = AnimationUtility.GetAnimationClipSettings(clip);
        settings.loopTime = true;
        settings.stopTime = (sprites.Length + 1) * frame;
        AnimationUtility.SetAnimationClipSettings(clip, settings);
        AssetDatabase.CreateAsset(clip, "Assets/Animations/hero_run.anim");
    }
}

Les temps des clés sont en secondes, donc un maintien est un écart plus large entre les clés. Définissez stopTime pour que la dernière image ait sa durée complète.

  • Dans l'Animator, les transitions de sprite veulent généralement Has Exit Time désactivé et Transition Duration 0, sinon la pose suivante arrive en retard.
  • animator.Play(hash) laisse un état qui joue déjà seul, donc l'appeler à chaque mise à jour est sûr. Rejouer un plan unique nécessite Play(hash, 0, 0f). Hachez les noms une fois avec Animator.StringToHash.
  • Détectez la fin d'un plan unique avec un Animation Event, ou vérifiez normalizedTime >= 1 tandis que IsInTransition(0) est faux et que le hash d'état correspond. Une transition peut sinon rapporter l'ancien état.
  • Mettez l'Animator et le SpriteRenderer sur un enfant, avec le Rigidbody2D et le collider sur la racine, et désactivez Apply Root Motion. flipX ne retourne pas les colliders ou les objets enfants, et il reflète autour du pivot, donc un pivot décentré saute.
  • Les maillages de sprite serrés peuvent couper les effets dessinés sur l'image ; utilisez Full Rect lorsqu'un shader échantillonne au-delà du contour.
  • Un Sprite Atlas regroupe les images importées séparément. Donnez-lui du remplissage, et désactivez Tight Packing et Allow Rotation pour le pixel art.

Pièges : mauvais → bon

MauvaisBon, et pourquoi
Trier les noms de fichiers sans remplissage lexicographiquementOrdre explicite ; frame-10 précède sinon frame-2
Rogner chaque image indépendammentGardez la toile ou des décalages valides pour que les pieds restent plantés
Deviner les noms de base empaquetésLisez les clés de descripteur et les chemins de sortie retournés
Utiliser la même unité de durée dans chaque moteurGodot utilise des multiplicateurs relatifs, Phaser ajoute la durée d'image en millisecondes, Unity les clés sont en secondes
Appeler play(clé) à chaque mise à jourplay(clé, true) évite de redémarrer un clip déjà actif
Laisser la vitesse visuelle du clip changer les dégâts ou la physique implicitementGardez le timing du gameplay comme autorité sauf couplage explicite

Terminé quand

  • Le nombre réel d'images, l'ordre des images, le timing du clip, la boucle et le comportement d'un plan unique correspondent à la demande.
  • Les pieds et les pivots restent stables lors des transitions entre repos et course, du miroir et du redémarrage ; pixo asset frames check rapporte ok pour chaque état, ou ses problèmes restants sont délibérés.
  • Les références d'atlas et les chemins de chargement sont réels ; les changements visuels préservent le comportement de collision.
  • Utilisez pixo game run <projectId> --json, ou l'Éditeur sur Unity, pour regarder les boucles complètes et l'achèvement des plans uniques ; une image fixe ne peut pas prouver le timing. Rapportez les timings testés et les problèmes non résolus.
  • Inspectez pixo game verify --steps check,build,run --screenshot --json, y compris les erreurs de ressources et les étapes ignorées.

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Skills associés