Avez-vous deja souhaite pouvoir previsualiser un parcours cycliste avant de le parcourir ? Nous avons construit un systeme automatise qui genere de magnifiques videos de survol pour chaque parcours de fete sur Party Onbici, offrant aux cyclistes un apercu cinematographique de ce qui les attend sur leur trajet.

Le Defi

Lors de l’organisation ou de la participation a un evenement cycliste, comprendre le parcours est crucial. Les cartes statiques sont utiles, mais elles ne transmettent pas l’experience de parcourir reellement l’itineraire. Nous voulions donner aux utilisateurs un moyen de “survoler virtuellement” le parcours avant de s’engager dans une sortie.

Notre Solution : Rendu Video Headless

Nous avons construit un service Node.js qui execute un navigateur Chrome headless utilisant Puppeteer, rend le parcours sur une carte interactive MapLibre GL, et capture des images tandis qu’une camera virtuelle survole le chemin. Voici comment cela fonctionne :

1. Interpolation du Parcours

Un parcours cycliste peut avoir des milliers de points de coordonnees. Pour creer une video fluide a 30 FPS pendant 15 secondes, nous avons besoin d’exactement 450 images. Nous utilisons l’interpolation basee sur la distance pour echantillonner le parcours uniformement :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Calculate cumulative distances using Haversine formula
const distances = [0];
for (let i = 1; i < coordinates.length; i++) {
  const dist = haversineDistance(coordinates[i-1], coordinates[i]);
  totalDistance += dist;
  distances.push(totalDistance);
}

// Sample at exactly totalFrames points
for (let frame = 0; frame < totalFrames; frame++) {
  const targetDist = (frame / (totalFrames - 1)) * totalDistance;
  // Interpolate position at this distance...
}

2. Animation de Camera avec Orientation Fluide

Simplement pointer la camera dans la direction du deplacement cree des mouvements saccades sur les parcours sinueux. Nous lissons l’orientation de la camera en utilisant une moyenne mobile sur 12 images, avec un traitement special pour le passage 360 degres/0 degre :

1
2
3
4
5
6
7
// Use sin/cos components for circular averaging
for (let j = i - smoothWindow; j <= i + smoothWindow; j++) {
  const rad = rawBearings[j] * Math.PI / 180;
  sinSum += Math.sin(rad);
  cosSum += Math.cos(rad);
}
const avgBearing = Math.atan2(sinSum/count, cosSum/count) * 180 / Math.PI;

3. Rendu MapLibre GL

Le parcours est rendu sur une belle couche de base Stadia Maps avec :

  • Une ligne de parcours mise en evidence avec un contour blanc pour la visibilite
  • Un indicateur anime de position de camera
  • Des marqueurs de depart (vert) et d’arrivee (rouge)
  • Des extrusions optionnelles de batiments 3D pour les zones urbaines

4. Capture d’Images et Encodage Video

Puppeteer capture chaque image sous forme de capture d’ecran PNG, puis nous utilisons ffmpeg pour les encoder en video WebM avec le codec VP9 :

1
2
3
ffmpeg -framerate 30 -i frame_%05d.png \
  -c:v libvpx-vp9 -crf 20 -b:v 0 \
  route.webm

Architecture Technique

1
Django App → Celery Task → Node.js Renderer → S3 Storage
  1. Django declenche la generation video lorsqu’une fete est creee ou mise a jour
  2. Celery met en file d’attente la tache pour un traitement asynchrone
  3. Le moteur de rendu Node.js execute Puppeteer avec MapLibre GL
  4. ffmpeg encode les images capturees
  5. La video est telechargee vers S3 et l’enregistrement de la fete est mis a jour

Considerations de Performance

ResolutionDureeTemps de RenduTaille du Fichier
1280x72015s60-90s2-4 Mo
1920x108015s90-120s4-8 Mo

Pour la production, nous utilisons des conteneurs Docker avec rendu logiciel (SwiftShader) pour eviter les dependances GPU :

1
2
--use-angle=swiftshader
--enable-unsafe-swiftshader

Fonctionnalites Ajoutees

  • Dimensions video personnalisables - Format carre pour le partage sur les reseaux sociaux
  • Filigrane avec logo - Personnalisez vos videos avec le logo de votre organisation
  • Inclinaison et zoom de camera - Ajustez l’angle de vue et l’altitude
  • Style de ligne de parcours - Couleurs et largeurs personnalisees

Integration Django

Depuis le code de l’application, generer une video est aussi simple que :

1
2
party = Party.objects.get(uid="...")
party.generate_video(width=1080, height=1080, duration=10)

L’URL de la video est automatiquement mise a jour lorsque le rendu est termine :

1
2
3
4
5
{% if party.video_url %}
<video controls>
  <source src="{{ party.video_full_url }}" type="video/webm">
</video>
{% endif %}

Prochaines Etapes

Nous explorons plusieurs ameliorations :

  • Apercu en temps reel - Rendu en direct pendant que les utilisateurs dessinent des parcours
  • Angles de camera multiples - Vues laterales, prises de vue aeriennes
  • Superposition meteo - Afficher les conditions prevues le long du parcours
  • Profil d’elevation - Visualiser les montees et descentes dans la video

Les videos de survol de parcours sont devenues l’une de nos fonctionnalites les plus populaires, aidant les cyclistes a prendre des decisions eclairees sur les sorties a rejoindre. La combinaison des technologies web modernes transforme ce qui aurait ete une tache de production couteuse en un service automatise et a la demande.


Vous voulez l’essayer ? Creez une fete et votre video de parcours sera automatiquement generee !