Problème: l'onglet Calques était inutile (vide en pratique), et le studio
Génération IA mélangeait création (prompts) et post-production (déplacer,
annoter, inpainter). Mental model confus.
Solution: séparation claire des responsabilités:
# STUDIO GÉNÉRATION (onglet "Génération IA")
Recentré sur sa mission unique: produire du contenu IA brut.
- Prompt + style + N variantes + galeries
- Preview live (CompositePreview empile bg+fg actifs)
- 3 modes preview: Live / Figé / Original
- Bouton "Figer composite"
- SUPPRIMÉ: toolbar OUTILS (Manipuler/Annoter) - déménagent en Composition
- Hint vers l'onglet Composition pour les retouches
# STUDIO COMPOSITION (onglet "Calques" renommé "Composition")
Nouveau composant CompositionStudio (550 lignes) avec 3 zones:
- Gauche (260px): Liste layers avec drag-drop, visible/lock/opacity
- Centre (1fr): Canvas live, toolbar Sélection/Manipuler/Annoter,
bouton "Figer composite", overlays LayerManipulator + AnnotationCanvas
- Droite (280px): Inspecteur du layer sélectionné
* Name editable
* Source visuelle (variant picker pour changer la source)
* Opacity slider, blend mode
* Transform display (modifié via outil Manipuler)
* Masque preview + clear
* Dupliquer / Supprimer
# MODÈLE DE DONNÉES UNIFIÉ
Table layers enrichie (migration ALTER TABLE):
- frameId (composition est par-frame)
- sourceVariantId (FK vers frameVariants - réutilisable)
- imageUrl (pour layers d'effets/objets sans variant source)
- blendMode (normal/multiply/screen/overlay)
- transform JSON (x, y, scale, rotation, flipH, flipV)
- maskUrl spécifique au layer
# AUTO-CRÉATION DES LAYERS
Lors de generation.regenerateBackground/Character:
- Création/sync d'un layer correspondant via upsertLayerForVariant
- name auto ("Arrière-plan IA" / "Personnage IA")
- sourceVariantId pointe vers la variante générée
- order: 0 pour bg, 1 pour character
# COMPOSITING SERVEUR REFONDU
compositing.composeFrame utilise désormais les layers DB:
- Itère sur listLayersForFrame(frameId)
- Résout chaque imageUrl via sourceVariantId ou imageUrl direct
- Applique opacity, blendMode, transform, maskUrl du layer
- Fallback sur les anciens champs frame.regenerated*Url si pas de layers
# NOUVEAUX ENDPOINTS tRPC
- layers.listForFrame(frameId)
- layers.patch (toutes propriétés partielles)
- layers.duplicate(layerId)
- layers.createCustom(frameId, type, name, imageUrl?)
- (existant: reorder, toggleVisibility, toggleLock, delete, create)
# MIGRATION DES DONNÉES EXISTANTES
Script créé: 14 layers générés à partir des frameVariants actives
de 10 frames qui n'avaient pas de layers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>