Animations custom (video/GIF) + selection aleatoire

- Upload de GIF/MP4/WebM comme animations de compte a rebours
- Checkboxes pour activer/desactiver chaque animation (CSS + custom)
- Si plusieurs actives, tirage aleatoire a chaque photo
- Preview dans le backoffice avec tirage aleatoire
- Suppression des animations custom importees
- Les animations custom se jouent en plein ecran avant la capture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 23:29:02 +01:00
parent a525f72800
commit cbe514bb93
7 changed files with 342 additions and 56 deletions

View File

@@ -76,32 +76,83 @@ function getNombrePhotos() {
return 1;
}
function choisirAnimationAleatoire() {
// Construire la liste de toutes les animations actives (CSS + custom)
const cssActives = config.camera?.animations_css_actives || ['classique'];
const customActives = config.animations_custom?.actives || [];
const pool = [
...cssActives.map(id => ({ type: 'css', id })),
...customActives.map(nom => ({ type: 'custom', nom })),
];
if (pool.length === 0) return { type: 'css', id: 'classique' };
return pool[Math.floor(Math.random() * pool.length)];
}
async function compteARebours() {
const conteneur = document.getElementById('compte-a-rebours');
const chiffre = document.getElementById('chiffre-car');
const duree = config.camera?.compte_a_rebours || 3;
const anim = config.camera?.animation_compte_a_rebours || 'classique';
conteneur.classList.remove('cache');
// Choisir une animation au hasard parmi les actives
const anim = choisirAnimationAleatoire();
for (let i = duree; i > 0; i--) {
// Contenu selon le type d'animation
if (anim === 'emoji') {
chiffre.textContent = EMOJI_CAR[i] || i;
} else {
chiffre.textContent = i;
if (anim.type === 'custom') {
// Jouer une video/gif en plein ecran
await jouerAnimationCustom(anim.nom, duree);
} else {
// Animation CSS classique
conteneur.classList.remove('cache');
for (let i = duree; i > 0; i--) {
if (anim.id === 'emoji') {
chiffre.textContent = EMOJI_CAR[i] || i;
} else {
chiffre.textContent = i;
}
chiffre.className = 'anim-chiffre';
void chiffre.offsetWidth;
chiffre.classList.add('anim-' + anim.id);
await pause(1000);
}
// Appliquer l'animation
chiffre.className = 'anim-chiffre anim-' + anim;
chiffre.style.animation = 'none';
chiffre.offsetHeight;
chiffre.className = 'anim-chiffre anim-' + anim;
conteneur.classList.add('cache');
}
}
await pause(1000);
async function jouerAnimationCustom(nom, duree) {
// Creer un overlay plein ecran pour la video/gif
const overlay = document.createElement('div');
overlay.className = 'video-countdown-overlay';
const ext = nom.split('.').pop().toLowerCase();
if (ext === 'gif') {
const img = document.createElement('img');
img.src = `/assets/animations/${nom}`;
overlay.appendChild(img);
document.body.appendChild(overlay);
await pause(duree * 1000);
} else {
const video = document.createElement('video');
video.src = `/assets/animations/${nom}`;
video.muted = true;
video.playsInline = true;
video.autoplay = true;
overlay.appendChild(video);
document.body.appendChild(overlay);
// Attendre la fin de la video ou le timeout
await Promise.race([
new Promise(resolve => { video.onended = resolve; }),
pause(duree * 1000 + 2000),
]);
}
conteneur.classList.add('cache');
overlay.remove();
}
function afficherFlash() {