Compare commits

..

7 commits

Author SHA1 Message Date
isUnknown
3a2b5a2f57 Perf: optimisation vidéos page expertise
All checks were successful
Deploy / Deploy to Production (push) Successful in 21s
- Vidéos recompressées (CRF 23, faststart) : 13MB → 3.4MB et 3.7MB
- Champs Kirby dynamiques pour vidéo normale et inverse
- Sources dynamiques via data.backgroundVideo / data.backgroundVideoReverse

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:54:49 +01:00
isUnknown
84744cd4a3 Fix: home.yml — nettoyage blueprint vidéo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:49:15 +01:00
isUnknown
0b3d2e3dbc Docs: retrait WebM VP9 — un seul champ vidéo par source dans Kirby
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:48:38 +01:00
isUnknown
8d6f943375 Docs: présentation FFmpeg et méthodes d'installation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:47:18 +01:00
isUnknown
af4d6200c6 Docs: guide de choix entre H.264 et WebM VP9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:46:42 +01:00
isUnknown
5c77e4817d Docs: commandes FFmpeg pour compression vidéo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:40:18 +01:00
isUnknown
2373b81db7 Perf: optimisation vidéos page d'accueil
- Vidéos recompressées (CRF 23, faststart, full res/fps) : 22MB → 5.8MB et 4.8MB
- Champs Kirby dynamiques pour vidéo desktop/mobile + posters
- Source vidéo dynamique via data.backgroundVideo (corrige le hardcode)
- Lecture déclenchée sur canplay plutôt qu'immédiatement (évite freeze)
- preload="auto" pour un buffering plus agressif

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:39:19 +01:00
11 changed files with 156 additions and 41 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

48
docs/ffmpeg.md Normal file
View file

@ -0,0 +1,48 @@
# Commandes FFmpeg
## Qu'est-ce que FFmpeg ?
FFmpeg est un outil en ligne de commande open source pour traiter des fichiers audio et vidéo : conversion de formats, compression, extraction de frames, redimensionnement, etc. C'est la référence dans le domaine, utilisée par VLC, YouTube et la plupart des plateformes vidéo en coulisses.
### Installation
**macOS** (via Homebrew) :
```bash
brew install ffmpeg
```
**Linux (Debian/Ubuntu)** :
```bash
sudo apt install ffmpeg
```
**Windows** : télécharger le build depuis [ffmpeg.org/download.html](https://ffmpeg.org/download.html) et ajouter le dossier `bin/` au PATH.
Vérifier l'installation :
```bash
ffmpeg -version
```
---
## Compression vidéo (page d'accueil)
Compresse sans perte de résolution ni de framerate. CRF 23 = qualité par défaut libx264. `faststart` place l'atome `moov` en tête du fichier pour un démarrage immédiat en streaming.
```bash
# Desktop (1920x1080, 30fps) — 22MB → 5.8MB
ffmpeg -i Website_version.mp4 \
-c:v libx264 -preset slow -crf 23 -an -movflags +faststart \
Website_version_opt.mp4
# Mobile (1080x1920, 30fps) — 22MB → 4.8MB
ffmpeg -i mobile_version_texte_fixe.mp4 \
-c:v libx264 -preset slow -crf 23 -an -movflags +faststart \
mobile_version_opt.mp4
```
## Notes
- `-an` : supprime la piste audio (inutile pour des vidéos `muted` en fond)
- `-preset slow` : meilleure compression à qualité égale (encode plus lentement)
- `crf` : Constant Rate Factor — plus bas = meilleure qualité. 23 = défaut libx264, 18 = quasi-lossless

View file

@ -53,3 +53,37 @@ tabs:
- heading
headings:
- 3
media:
label: Médias
icon: image
columns:
- width: 1/2
sections:
mediaFields:
type: fields
fields:
backgroundVideo:
label: Vidéo d'arrière-plan (sens normal)
type: files
layout: cards
max: 1
accept: video/*
translate: false
image:
ratio: 16/9
cover: true
uploads:
template: video
backgroundVideoReverse:
label: Vidéo d'arrière-plan (sens inverse)
type: files
layout: cards
max: 1
accept: video/*
translate: false
image:
ratio: 16/9
cover: true
uploads:
template: video

View file

@ -41,9 +41,8 @@ tabs:
type: fields
fields:
backgroundVideo:
label: Vidéo d'arrière-plan
label: Vidéo d'arrière-plan (desktop)
type: files
layout: cards
max: 1
accept: video/*
translate: false
@ -52,3 +51,36 @@ tabs:
cover: true
uploads:
template: video
backgroundVideoPoster:
label: Poster vidéo desktop
type: files
layout: cards
max: 1
accept: image/*
translate: false
image:
ratio: 16/9
cover: true
help: Image affichée au besoin pendant le chargement de la vidéo
backgroundVideoMobile:
label: Vidéo d'arrière-plan (mobile)
type: files
max: 1
accept: video/*
translate: false
image:
ratio: 9/16
cover: true
uploads:
template: video
backgroundVideoMobilePoster:
label: Poster vidéo mobile
type: files
layout: cards
max: 1
accept: image/*
translate: false
image:
ratio: 9/16
cover: true
help: Image affichée au besoin pendant le chargement de la vidéo

View file

@ -1,8 +1,10 @@
<?php
$specificData = [
'pageTitle' => $page->writer()->value(),
'items' => $page->body()->toBlocks()->filter(fn($b) => $b->type() === 'text')->map(fn($block) => [
'pageTitle' => $page->writer()->value(),
'backgroundVideo' => $page->backgroundVideo()->toFile()?->url(),
'backgroundVideoReverse' => $page->backgroundVideoReverse()->toFile()?->url(),
'items' => $page->body()->toBlocks()->filter(fn($b) => $b->type() === 'text')->map(fn($block) => [
'text' => $block->text()->value()
])->values()
];

View file

@ -9,7 +9,10 @@ $specificData = [
'ctaPath' => $page->ctaLink()->toPage()?->id() ?? '#',
'image' => $page->heroImage()->toFile()?->url()
],
'backgroundVideo' => $page->backgroundVideo()->toFile()?->url(),
'backgroundVideo' => $page->backgroundVideo()->toFile()?->url(),
'backgroundVideoPoster' => $page->backgroundVideoPoster()->toFile()?->url(),
'backgroundVideoMobile' => $page->backgroundVideoMobile()->toFile()?->url(),
'backgroundVideoMobilePoster' => $page->backgroundVideoMobilePoster()->toFile()?->url(),
'floatingBubbles' => $page->floatingBubbles()->toStructure()->map(function($bubble) {
return [
'text' => $bubble->text()->value(),

View file

@ -232,7 +232,7 @@
playsinline
preload="auto"
>
<source src="/assets/video/BACKGROUND_VIDEO_MISSION.mp4" type="video/mp4" />
<source src={data.backgroundVideo ?? '/assets/video/BACKGROUND_VIDEO_MISSION.mp4'} type="video/mp4" />
</video>
<video
bind:this={videoRev}
@ -241,7 +241,7 @@
playsinline
preload="auto"
>
<source src="/assets/video/BACKGROUND_VIDEO_MISSION_REVERSE.mp4" type="video/mp4" />
<source src={data.backgroundVideoReverse ?? '/assets/video/BACKGROUND_VIDEO_MISSION_REVERSE.mp4'} type="video/mp4" />
</video>
</div>

View file

@ -7,36 +7,34 @@
const currentLang = $derived(locale.current)
onMount(() => {
const playVideo = async (videoId) => {
const video = document.getElementById(videoId)
if (video) {
try {
video.muted = true
video.playsInline = true
const playPromise = video.play()
if (playPromise !== undefined) {
await playPromise
}
} catch (error) {
console.log(`Autoplay failed for ${videoId}:`, error)
const playOnInteraction = () => {
video.play().catch(e => console.log('Fallback play failed:', e))
document.removeEventListener('click', playOnInteraction)
document.removeEventListener('touchstart', playOnInteraction)
}
document.addEventListener('click', playOnInteraction)
document.addEventListener('touchstart', playOnInteraction)
function playWhenReady(video) {
if (!video) return
const attempt = () => {
video.muted = true
video.playsInline = true
video.play().catch(() => {
// Autoplay bloqué : on attend une interaction
const onInteraction = () => {
video.play().catch(() => {})
document.removeEventListener('click', onInteraction)
document.removeEventListener('touchstart', onInteraction)
}
}
document.addEventListener('click', onInteraction)
document.addEventListener('touchstart', onInteraction)
})
}
const timer = setTimeout(() => {
playVideo('home-video')
playVideo('home-video-mobile')
}, 100)
if (video.readyState >= 3) {
attempt()
} else {
video.addEventListener('canplay', attempt, { once: true })
}
}
return () => clearTimeout(timer)
onMount(() => {
playWhenReady(document.getElementById('home-video'))
playWhenReady(document.getElementById('home-video-mobile'))
})
function handleExplore() {
@ -49,27 +47,25 @@
<figure class="home-figure">
<video
muted
autoplay
playsinline
loop
controls={false}
preload="metadata"
preload="auto"
id="home-video"
class="home-video home-video-desktop"
poster={data.backgroundVideoPoster ?? undefined}
>
<source src="/assets/video/Website_version.mp4" type="video/mp4" />
<source src={data.backgroundVideo ?? '/assets/video/Website_version.mp4'} type="video/mp4" />
</video>
<video
muted
autoplay
playsinline
loop
controls={false}
preload="metadata"
preload="auto"
id="home-video-mobile"
class="home-video home-video-mobile"
poster={data.backgroundVideoMobilePoster ?? undefined}
>
<source src="/assets/video/mobile_version_texte_fixe.mp4" type="video/mp4" />
<source src={data.backgroundVideoMobile ?? '/assets/video/mobile_version_texte_fixe.mp4'} type="video/mp4" />
</video>
</figure>
</div>