Décider quoi manger, en quelques swipes.
« Je ne sais jamais quoi manger ce soir » est une friction quotidienne. Les apps de recettes résolvent la découverte, des milliers de résultats pour un mot-clé, mais pas la décision : trop de choix, aucune mémoire des goûts, aucune réponse directe à « et là, maintenant ? ». L'hypothèse de Croque : le geste de swipe est le bon outil d'entrée. Il est binaire, rapide, sans charge cognitive, et chaque geste est une donnée. En quelques dizaines de swipes, l'app en sait assez pour arrêter de proposer et commencer à décider.
Ce que fait l'app
- Onboarding en six étapes (cuisines par continent, aliments bannis, régime, allergies, niveau et temps, budget et envies), entièrement facultatif et modifiable ensuite.
- Swipe : cartes plein écran, glisser-déposer avec rotation et retour physique, stickers « Miam » et « Nope », annulation du dernier geste, filtre Plats ou Desserts.
- Apprentissage continu : chaque swipe met à jour un profil de goûts multidimensionnel, et le paquet de cartes suivant est reconstruit à partir de ce profil.
- Match : un like sur une recette jugée très compatible déclenche un écran plein écran avec confettis et ajout direct aux coups de cœur.
- Mon livre : les recettes aimées, recherche floue qui tolère les fautes et les pluriels, filtres, tri, favoris.
- « Je mange quoi ce soir ? » : un tirage pondéré parmi les recettes compatibles, avec des critères facultatifs : temps disponible, budget, nombre de convives, envie du moment, ingrédients déjà au frigo.
- Profil : statistiques de swipe, « type culinaire » généré dynamiquement (par exemple Italo-épicé), barres de goût, badges.
Un moteur de recommandation lisible
Chaque recette est décomposée en features pondérées : la cuisine pèse 3, le type de plat 2, un tag comme « épicé » ou « rapide » 1,4, la protéine 1,2, la catégorie et la durée 1, la difficulté et le coût 0,6. Le poids de la cuisine domine volontairement : c'est le facteur le plus prédictif d'un like. Pour chaque feature vue, l'app compte les likes et les dislikes puis calcule une affinité lissée (lissage de Laplace) : affinité = (likes + 1) / (likes + dislikes + 2). Une feature jamais vue vaut 0,5, et une feature vue une seule fois ne bascule jamais à 0 ou 1 : le système ne sur-réagit pas à un swipe isolé. Les 20 derniers swipes comptent plein pot, les plus anciens décroissent jusqu'à un plancher de 0,6, pour que le profil suive des goûts qui évoluent.
Fusionner le déclaré et l'observé
Deux scores coexistent pour chaque recette : un score explicite dérivé de l'onboarding et un score appris, moyenne pondérée des affinités. Ils sont mélangés selon une confiance qui grandit avec le nombre de swipes : confiance = min(1, swipes / 16), poids appris = 0,65 × confiance. Au début, l'app s'appuie sur ce que l'utilisateur a déclaré ; après une quinzaine de swipes, le comportement réel prend le dessus, jusqu'à 65 % du poids mais jamais 100 %. Les allergies, elles, excluent en dur.
Construire le fil : classement, diversité, exploration
- Un peu de bruit (plus ou moins 0,04) à chaque reclassement, pour que deux sessions ne montrent jamais le même ordre à score égal.
- Une pénalité de diversité : une recette perd 0,09 point par répétition de sa cuisine parmi les deux dernières cartes, pour éviter cinq plats italiens d'affilée.
- De l'exploration : une carte sur quatre est tirée au hasard dans le milieu du classement (entre le 30e et le 70e centile). Sans elle, le profil ne découvrirait jamais qu'il aime aussi la cuisine éthiopienne.
Le match, calibré à l'usage
Le score brut est étiré en pourcentage de compatibilité (compat = 50 + (score − 0,5) × 140) pour que l'écart se voie à l'écran. Le seuil de match est fixé à 90 %. Un premier réglage à 85 % déclenchait un match presque à chaque like après quinze swipes, ce qui vidait le moment de sa surprise ; le remonter a redonné au match sa rareté, condition de son effet.
« Je mange quoi ce soir ? » : une décision sous contrainte
Le temps et le budget disponibles filtrent en dur. Des bonus contextuels s'ajoutent ensuite au score de goût : jusqu'à +0,24 si la recette utilise des ingrédients déjà au frigo, +0,12 à +0,20 si elle correspond à l'envie du moment (et −0,12 sinon), +0,08 si elle est déjà dans le livre. Plutôt que de renvoyer le meilleur score, l'app tire au sort parmi les six meilleures, avec des poids qui favorisent la tête sans jamais la rendre certaine : relancer propose autre chose de pertinent, jamais un doublon.
Un catalogue pensé comme un produit
187 recettes originales couvrant 54 cuisines sur cinq continents, avec des ingrédients quantifiés et mis à l'échelle selon le nombre de convives, des étapes réelles, et une photo vérifiée une à une (banques libres de droits) pour correspondre au plat décrit. Un ton éditorial cohérent : une punchline par recette, des « red flags » et « green flags » générés selon le profil (« Red flag : 47 minutes de préparation », « Green flag : ça pique, comme tu aimes »).
Architecture et stack
- Le dossier domain ne sait pas que React existe : types, taxonomie et moteur de recommandation sont des fonctions pures, testables isolément et remplaçables par un vrai modèle de ML sans toucher un composant.
- React 18, TypeScript strict (zéro any implicite), Vite, Tailwind CSS avec des tokens posés une fois, Framer Motion pour le seul geste vraiment orchestré, le swipe, React Router pour une app bookmarkable.
- Zustand : trois stores indépendants persistés dans le navigateur. Aucun backend : le produit prouve sa valeur sans compte, et un RecipeRepository isole la persistance pour qu'une synchro cloud se greffe plus tard.
- Environ 10 000 lignes de TypeScript, 58 fichiers, déploiement statique sur Vercel.
Design et qualité
Une identité propre plutôt qu'un décalque de Tinder : fond vert profond façon bistro de nuit, jaune beurre pour l'action, rouge tomate réservé au like et au match, un sticker de cagette à fruits en motif signature, typographie Bricolage Grotesque auto-hébergée, le tout documenté dans un fichier de design. CI GitHub Actions à chaque push (type-check strict puis build) et revue visuelle automatisée : un harnais Puppeteer rejoue onboarding, swipe, match, livre et profil sur mobile et desktop pour attraper les régressions qu'un compilateur ne voit pas.
Limites et suite
Les données restent sur l'appareil : changer de navigateur repart de zéro. Le scoring est un système de règles calibré à la main, choix assumé pour une V1 simple, explicable et déboguable. Pistes : comptes et synchronisation, analyse du frigo par photo, liste de courses automatique, recommandations saisonnières, import de recettes depuis une URL, puis remplacement du moteur par un modèle appris sur des données réelles.