L'utilisateur peut désormais déplacer, redimensionner, rotater et
flipper le personnage généré sans devoir tout régénérer.
DB:
- Nouveau champ transform JSON sur frameVariants
- Format: {x, y, scale, rotation, flipH, flipV} avec coords relatives
Backend (sharp):
- compositeLayers applique transform avant le blend:
* scale: resize layer (peut être >100% ou <100%)
* rotation: sharp.rotate avec fond transparent
* flipH/flipV: flop/flip
* x/y: offset en pourcentage de la base (centré + delta)
- Gestion intelligente des layers qui dépassent: extract crop
(sharp interdit top/left négatifs et inputs plus grands que la base)
- compositing.composeFrame récupère le transform de la variant
character active automatiquement
- Nouveau endpoint frameVariants.updateTransform
Frontend (LayerManipulator):
- Composant overlay avec bounding box pointillée + 8 handles
- Handles coins = scale, handle haut = rotation, area centrale = move
- CSS transform live (translate/scale/rotate/scaleX(-1) pour flip)
- Toolbar flottante: flip H/V, position/scale/rotation affichés en live
- Reset button quand transformé
- Bouton "Recomposer" déclenche composeFrame avec le nouveau transform
- Save backend automatique au release de souris
ViewportPanel:
- Bouton "Manipuler" dans toolbar (visible uniquement mode composite)
- Active LayerManipulator overlay, mutuellement exclusif avec Annoter/Loupe
- Désactivé si pas de variant character actif (toast warn)
Workflow:
1. Mode composite dans viewport
2. Click "Manipuler" → handles apparaissent
3. Drag pour déplacer / corners pour scale / handle haut pour rotation
4. Sauvegarde auto au release (en DB)
5. Click "Recomposer" → sharp regenère avec transform appliqué
6. Nouvelle variante composite créée (Module 1)
7. La galerie M1 montre l'avant/après
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Format ratio (60):
- OpenAI gpt-image-1: choix automatique de size (1024x1024 / 1536x1024 /
1024x1536) selon ratio cible le plus proche
- Crop sharp post-génération pour matcher EXACTEMENT le ratio source
- segmentationService passe les dimensions du projet (width/height)
à regenerateBackground et regenerateCharacter
- Routes generation.* récupèrent project.width/height depuis DB
- Testé: frame 25 (854x480) -> bg généré en 854x480 exact
Redirect bug (61):
- DashboardLayout: navigate("/login") déplacé du render vers useEffect
(anti-pattern React fix)
- main.tsx redirectToLoginIfUnauthorized: préserve l'URL d'origine
dans ?return=...
- Login.tsx onSuccess: redirige vers ?return URL au lieu de "/"
- Plus de retour à l'accueil après refresh ou opération
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Nouvel onglet "Génération IA" dans le workspace avec 2 boutons:
* Regénérer l'arrière-plan (prompt + style)
* Redessiner le personnage (prompt + sélecteur de character sheet)
- 3 endpoints tRPC: generation.regenerateBackground,
generation.regenerateCharacter, generation.inpaintBackground
- Fix URLs relatives -> signed URLs S3 absolues pour l'API Forge
- Résultat affiché en preview dans le panneau
- Testé: génération cyberpunk sur frame 200 -> PNG 1344x768 OK
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>