BeReal rencontre GeoGuessr : un lieu par jour, il faut y aller pour marquer.
Chaque jour, l'application désigne un lieu de Vannes, le même pour tout le monde. Pour marquer des points, il faut s'y rendre : la photo n'est acceptée qu'à moins de cent mètres du lieu, GPS à l'appui. Chaque lieu s'accompagne d'une courte note historique, ce qui transforme la partie en visite guidée sans le vouloir.
L'idée de départ : on passe devant les mêmes rues tous les jours sans jamais s'arrêter. Une contrainte ludique suffit parfois à changer ça.
Une partie tient en quatre temps.
Le tirage. À minuit, chaque téléphone calcule le lieu du jour. Personne ne l'écrit dans la base, personne ne peut le choisir.
Sur place. La carte montre le lieu et sa zone de cent mètres. L'anneau se remplit à mesure qu'on approche, et le bouton ne s'allume qu'une fois dedans.
Le mur du jour. Les photos des autres restent verrouillées tant qu'on n'a pas publié la sienne.
Le rappel. Une notification par jour, à une heure qui change tous les jours mais tombe au même moment pour tout le monde.
Une application Flutter pour Android, avec Firebase derrière : Authentication pour les comptes, Firestore pour les joueurs, les validations et les photos. Les photos y tiennent sans peine, en 3:4 de 900 × 1200 pixels, et Cloud Storage n'est plus offert sur le forfait gratuit de Firebase : tout le jeu tourne sans rien payer. La carte vient d'OpenStreetMap, sans clé d'API.
Trois pièces tiennent le jeu.
Une validation traverse cinq étapes, et tout passe d'un bloc ou rien ne passe.
Le téléphone ne fait que proposer ses points : Firestore refait le calcul et refuse ce qui ne tombe pas juste.
Les points se calculent au jour près : dix par lieu, deux de plus par jour de série, et le bonus s'arrête à dix.
Les photos, elles, sont toutes au même format, quel que soit l'appareil.
Le code est rangé en couches : lib/domain pour les règles du jeu, sans Flutter ni Firebase, et testé ; lib/data pour le stockage, avec une version Firebase et une version de démonstration en mémoire ; lib/ui pour les écrans.
Côté interface, chaque animation a un rôle : un radar marque le lieu sur la carte, une jauge se remplit en approchant, un reflet passe sur le bouton quand il devient utile, et la validation se fête avec une coche qui se dessine et une gerbe de confettis. Les écrans s'installent bloc par bloc, et les marches du podium montent.
Deux applications, qui s'installent côte à côte sans se gêner.
- BeVannes, la version complète : le vrai jeu, relié au serveur. Un compte, le classement, les photos et les séries partagés avec les autres joueurs.
- BeVannes démo : une petite communauté fictive, tout reste sur le téléphone, et un interrupteur « Me téléporter sur le lieu » pour essayer la validation sans traverser Vannes.
Les deux sont signées par la même clé ; une mise à jour s'installe par-dessus la précédente sans rien perdre.
# SHA-256 de BeVannes.apk, version 2.1.0
8d25d9ecd2d6d0e5175adf36d63d6e58815335ea5c04ffd7bf8e58b6c87ead7e
# SHA-256 de BeVannes-demo.apk, version 2.1.0
92d5c9d0592950c7ae3c6936ab28e98d11f1b93cf3128b468b4e34d2bfa81eaf
# SHA-256 du certificat de signature, CN=BeVannes, O=Cybertrist
9a8c67645db4e34f4585d84e1db2addf9cbbabc01539bfb4ff57277c0f00feeb
Pour construire, il faut Flutter. La démo se construit avec --dart-define=DEMO=true, qui lui donne aussi son propre identifiant, fr.bevannes.bevannes.demo.
git clone https://github.com/Cybertrist/BeVannes.git
cd BeVannes
flutter pub get
flutter run --dart-define=DEMO=truePour jouer pour de vrai, il faut un projet Firebase.
- Sur la console Firebase, activer Authentication (e-mail et mot de passe) et Firestore, et déclarer une application Android
fr.bevannes.bevannes. - Télécharger son
google-services.json, puis écrire la configuration de compilation, ignorée par git :
bash tool/firebase_env.sh chemin/vers/google-services.json- Déployer les règles et les index du dépôt :
firebase deploy --only firestore- Construire :
flutter build apk --release --dart-define-from-file=firebase.env.jsonLes clés d'API Firebase côté client ne sont pas des secrets, elles se lisent dans tout APK. Ce qui protège les données, ce sont les règles de
firestore.rules: un joueur n'écrit que ses propres points, recalculés par le serveur, et ne voit les photos d'un jour qu'après avoir validé ce jour-là.
Dix-neuf lieux aujourd'hui, de la cathédrale à la pointe de Conleau, qui passent chacun une fois par cycle.
Les lieux vivent dans assets/lieux.json, embarqués dans l'application.
{
"id": "lavoirs-garenne",
"nom": "Lavoirs de la Garenne",
"quartier": "Les remparts",
"latitude": 47.6555828,
"longitude": -2.7554577,
"note": "Sous leurs toits d'ardoise, au bord de la Marle, les lavandières rinçaient le linge jusqu'au milieu du XXe siècle."
}Les coordonnées se prennent sur OpenStreetMap, pas à l'œil : à cent mètres près, un lieu mal placé devient impossible à valider. La note n'est pas décorative non plus, c'est elle qui fait la différence entre une chasse au trésor et une visite.
L'ordre du fichier entre dans le tirage : ajouter un lieu rebat le cycle en cours. Tous les joueurs doivent donc avoir la même version de l'application pour voir le même lieu.
Le terrain de jeu est Vannes. Ailleurs, il n'y a rien à découvrir.
La position reste celle que le téléphone annonce. Android signale les applications de position fictive, et le jeu les refuse, mais un téléphone modifié peut mentir sans le dire. Les règles Firestore garantissent la cohérence des points, pas la présence sur place.
Les photos ne sont pas modérées, et les tuiles d'OpenStreetMap ne sont pas faites pour un gros trafic : au-delà d'un cercle d'amis, il faudrait un serveur de tuiles à soi.
Écrit en Flutter et Dart, avec Firebase. Licence MIT.
Projet étudiant · Université Bretagne Sud, Vannes · Tristan Joncour










