Fablebloom : pas de cartes cachées, pas de chrono, pas de boosters
Un jeu de cartes stratégique et paisible, dans le navigateur. Quatre-vingt-quatre cartes, quatre familles, trois clairières, et des règles qui refusent l'information cachée, le chrono de tour et les boosters aléatoires.

Le contexte
Fablebloom est un jeu de cartes stratégique qui tourne dans le navigateur. Deux Keepers se disputent le réveil d’un jardin endormi : vous installez de petites créatures, les Fablings, dans trois clairières (les Glades), et le premier Keeper qui en restaure deux met fin à la saison immédiatement. Une saison dure au plus huit Moons, soit une dizaine de minutes.
Quatre-vingt-quatre cartes, quatre familles, trois Glades. Gratuit, une boutique qui ne vend que du cosmétique, et aucun compte requis pour commencer.
C’est un produit Nuits, donc il est à moi de bout en bout, et il n’est pas terminé. Le nom et les illustrations sont provisoires en attendant la validation de la marque et du domaine, et les pages légales sont des brouillons de structure. C’est écrit sur le site lui-même : une page intitulée Our Promise qui cacherait son propre état ne serait pas une promesse.
Le problème
Les jeux de cartes numériques ont recours à trois outils qu’un jeu papier ne peut pas vraiment utiliser, et les trois portent quelque chose. L’information cachée fabrique de la tension gratuitement. Le chrono de tour fait avancer la partie sans demander aux joueurs d’être prévenants. Les boosters aléatoires transforment une collection de cartes en ligne de revenus modélisable dans un tableur.
Chacun rend aussi le jeu moins agréable à pratiquer. L’information cachée signifie que la décision intéressante a été prise pendant que vous regardiez ailleurs. Le chrono punit la réflexion, c’est-à-dire précisément ce dont le jeu prétend parler. Et une économie de boosters fait du meilleur deck un achat, si bien qu’une partie serrée ne sera jamais tout à fait un compliment.
Ce que je voulais, c’est le rythme d’un jeu de plateau posé sur une table, joué par deux personnes qui s’apprécient, en dix minutes, dans un onglet.
Mon rôle
Tout, seul. Nuits n’a jamais embauché personne.
Le game design et la collection de cartes, l’interface, le front, le déploiement, le site vitrine et les textes qui s’y trouvent, y compris le paragraphe qui reconnaît que le nom est provisoire.
L’approche
Trois refus, inscrits dans les règles plutôt que sur une page de valeurs : aucune information cachée qu’un joueur de jeu papier ne pourrait tenir en main, aucun chrono à l’intérieur des règles, et aucun hasard au-delà du mélange et de la pioche.
Tout le reste devait être construit pour y survivre. Sans chrono, la partie a besoin d’une horloge naturelle : une saison fait huit Moons, et chaque Moon s’achève quand les deux Keepers passent leur tour coup sur coup. Sans économie de boosters, la collection doit être finie et connaissable : il y a quatre-vingt-quatre cartes, toutes obtenues en jouant, et le Trading Post vend des cadres et des thèmes de plateau, rien qui touche à une règle.
La tension est passée dans la ressource. La Dew se recharge au numéro du Moon en cours et ne se reporte pas, donc le premier Moon est une décision unique et le septième est un plan. Personne ne peut économiser jusqu’à l’écrasement, et le joueur en retard dispose d’un budget plus large exactement au moment où la partie reste gagnable.
Chacune des trois Glades porte un seuil de floraison et une règle qui lui est propre. Sunny Meadow fait piocher le premier Keeper qui s’y installe. Ember Clearing fatigue d’un cran tout ce qui s’y trouve à la fin de chaque Moon. Firefly Hollow offre une carte la première fois, à chaque Moon, qu’un de vos Fablings s’épuise. En restaurer deux met fin à la saison : le plateau pose donc la question de savoir lesquelles deux, et non une course aux points.
Les quatre familles se distinguent par leur façon de jouer, pas par leur couleur, même si elles en ont une. Grove s’enracine et survit à la précipitation. Ember file vers une avance rapide et vous fatigue avant que vous soyez installé. Pond rallie les épuisés, donc lui répondre une fois n’est pas lui répondre. Sky dérive et vous renvoie chez vous, et vous croirez savoir où elle se tient.
Comme aucune règle ne contient de chrono, le jeu asynchrone est venu presque gratuitement. Une partie peut se dérouler à un tour par jour via un lien privé envoyé à une seule personne, et rien dans le jeu ne remarque la différence.
La construction
Cela a commencé sur Next.js, déployé sur Cloudflare Workers via OpenNext, pour que le jeu et le site qui le présente forment une seule base de code plutôt que deux. Il s’installe comme une application si vous le souhaitez et reste une page web sinon.
Il tourne désormais sur TanStack Start, c’est-à-dire un build Vite confié au plugin Vite de Cloudflare, qui produit un Worker sans rien entre les deux. La raison du changement, c’est que le framework répondait à une question que le jeu ne pose pas. Fablebloom est une application cliente déguisée en site vitrine : un plateau sans information cachée, c’est un état que le navigateur peut tenir en entier, donc une fois la partie lancée il n’y a plus rien à attendre du serveur.
Trois symptômes, dans l’ordre où ils sont devenus agaçants.
Les démarrages à froid. OpenNext embarquait le serveur Next.js lui-même dans le Worker, avec une couche de compatibilité Node, si bien que la première requête reçue par un isolat neuf payait le démarrage d’un framework avant de pouvoir répondre. Une réponse à chaud partait en 200 ms environ, une réponse à froid plutôt en 800 ms, et celui qui payait, c’était la personne qui avait ouvert l’onglet en premier.
Des navigations qui allaient chercher sur le réseau ce que le client savait déjà. Les en-têtes de réponse portaient vary: rsc, next-router-state-tree, next-router-prefetch, autrement dit l’App Router prévenait tous les caches qu’un changement de route est un aller-retour serveur. Passer des règles à une Glade puis à la liste des cartes en coûtait un à chaque fois, pour des pages dont le contenu n’avait pas bougé depuis le build.
Du poids qui arrivait avant le jeu. La page d’accueil vitrine envoyait environ 220 Ko de JavaScript compressé répartis en douze fragments avant qu’une seule carte soit piochée, essentiellement du framework, puis hydratait un arbre rendu côté serveur dont le client prenait la main aussitôt.
TanStack Start, c’est la même idée en plus petit. Les pages vitrine sont prérendues, le routeur se résout côté client, et des fonctions serveur couvrent les deux ou trois choses qui ont réellement besoin d’un serveur : un lien de partie, une sauvegarde, la connexion derrière la page de jeu. La frontière entre client et serveur est tracée là où l’application en a une, et non là où le framework supposait qu’elle serait.
Les statistiques passent par Umami, auto-hébergé plutôt que confié à une société d’analytics, comme pour tous les autres produits Nuits.
La contrainte intéressante est le premier refus. Un jeu sans information cachée n’a nulle part où ranger une erreur : les deux joueurs voient le plateau entier en permanence, donc tout écart entre ce que disent les règles et ce qu’affiche l’écran est visible par les deux en même temps. Cela pousse le corpus de règles à rester assez petit pour être énoncé en entier. Huit Moons, une action par tour, quatre types de cartes, trois règles de Glade, et une Dew qui se réinitialise. Un joueur qui soupçonne le jeu de s’être trompé peut vérifier, ce qui n’est possible que parce qu’il y a peu à vérifier.
Le résultat
Jouable et pas encore lancé. Le site est en ligne, les règles sont écrites, la collection est complète, et le nom posé sur l’ensemble est temporaire. La validation de la marque et du domaine vient avant un lancement, pas après, et tant qu’elle n’est pas obtenue il n’y a aucun intérêt à faire comme si la porte d’entrée était finie.
Ce que je ferais autrement
J’ai conçu quatre-vingt-quatre cartes et quatre familles avant que le nom soit validé. Si la validation se passe mal, rien du design des cartes n’est perdu et toutes les illustrations le sont, et cet ordre-là était évitable. La vérification juridique ennuyeuse coûte peu tôt et cher tard.
J’ai aussi choisi le framework avant de connaître la forme de l’application. Next.js est une bonne réponse à une question de pages, et Fablebloom s’est révélé être une question de plateau. Choisir un modèle de rendu d’abord, puis découvrir des mois plus tard que ce qu’on a construit est une application cliente, c’est une erreur qui ne se manifeste jamais autrement qu’en latence, et la migration en a été la facture.
J’ai aussi publié les pages légales sous forme de brouillons de structure, avec du texte provisoire. Je continue de penser qu’afficher le squelette avec une mention visible « pas encore contraignant » vaut mieux que de ne rien afficher, mais c’est étrange à laisser en ligne à côté d’une page qui décrit une boutique. La version honnête de cette phrase, c’est que la vitrine a été écrite avant les papiers.




