Développeur full-stackNantesOuvert aux offres

Tenu depuis le Dernière entrée 5 apps publiées · 1 en cours · 11 paquets

Adrien Lacourpaille

Ce que je code le soir, une fois la journée finie, une ligne datée par projet : les apps d’abord, puis les paquets qu’elles partagent. Je cherche mon prochain poste.

Registre des sorties, les apps puis les paquets

  1. Taverla

    App · jeux de soirée · en ligne

    Une étagère de jeux de soirée qui partagent une salle, un QR code et des écrans. Un écran mène la partie, les autres jouent sur ce qu’ils ont sous la main, et le premier qui sait remporte la manche.

    les 11 paquets maison

    Analytics

    Entrée complèteJouer en ligne (s’ouvre dans un nouvel onglet)
    Dessin : un écran hôte affichant le QR code de la salle et les joueurs installés, et un téléphone affichant le buzzerBUZZERScannez pour rejoindreINSTALLÉSAdaPREMIERGraceLinusMargaretProchaine manche bientôtSALLE · BUZZERAdaBUZZLe plus vif gagne la manche
    Dessiné pour ce registre, pas une capture
    Livré29 · IX · 2026

    Ce qui est livré

    1. Trois jeux sur la même étagère : blind test, buzzer et quiz.
    2. Une salle, un QR code : chacun rejoint depuis le téléphone qu’il a en main.
    3. Le serveur horodate chaque buzz : c’est la main la plus rapide qui gagne, pas l’horloge la plus en avance.
    4. Testé de bout en bout : de vrais sockets contre un vrai serveur, des parcours Playwright sur deux écrans.
    5. En anglais et en français, clair et sombre, sur un téléphone ou un portable.
    Code source (s’ouvre dans un nouvel onglet)

    Mécanisme · un serveur, un socket vers chaque écran

    Schéma : un serveur tient un WebSocket vers l’écran hôte et vers chaque téléphone, et horodate chaque buzz à son arrivéeUn serveurHono · date chaque buzzÉcran hôtemène la partie1er · gagne2e3e—WebSocket vers chaque téléphoneL’ordre se décide à l’arrivéesur le serveur, pas selonl’horloge des téléphones.
  2. on-record

    App · vie publique · en ligne

    Comment votent vraiment les députés, scrutin par scrutin. Chaque vote public de l’Assemblée nationale, expliqué en clair pour qui n’a jamais suivi une séance, chaque chiffre ramené au compte rendu officiel.

    les 11 paquets maison

    Analytics

    Entrée complèteOuvrir en ligne (s’ouvre dans un nouvel onglet)
    Dessin : un chiffre sur un député, relié au seul scrutin qu’il compte, sur une pile de feuilles de vote officielles où chaque ligne est un vote et chaque case un bulletinASSEMBLÉE NATIONALESCRUTINS PUBLICSUN CHIFFRE · UN DÉPUTÉPOURavec son groupe du jourSOURCE OFFICIELLEchaque page cite sa sourceCHAQUE CHIFFRErenvoie aux votes qu’il compteNI CLASSEMENT, NI NOTE
    Dessiné pour ce registre, pas une capture
    En ligne1 · X · 2026

    Ce qui est livré

    1. Chaque scrutin public de chaque député, avec le groupe où il siégeait le jour du vote. Ni classement ni note : chaque chiffre renvoie aux votes qu’il compte, et chaque page cite sa source officielle.
    2. Ni serveur ni base de données : chaque nuit, un job GitHub Actions demande à l’open data de l’Assemblée si quelque chose a changé, ne reconstruit que ce qui a bougé et déploie. Une nuit sans nouveau vote ne télécharge rien et ne déploie rien.
    3. L’hébergeur publie 20 000 fichiers par déploiement, et il y a plus de 8 000 scrutins : ils partent en blocs, un fichier par député, de petits index pour les listes et la recherche, et le build vérifie toute sa sortie contre un budget.
    4. Environ 750 pages prérendues par les loaders mêmes que le navigateur exécute, un faux fetch leur servant les données pendant le build, chacune avec ses propres balises head et sa place dans le sitemap.
    5. Trouver son député depuis sa commune ou son adresse, en français, en clair comme en sombre.
    Code source (s’ouvre dans un nouvel onglet)

    Mécanisme · pas de serveur, un job de nuit demande ce qui a changé

    Schéma : chaque nuit, un job GitHub Actions demande à l’open data de l’Assemblée si quelque chose a changé ; un nouveau vote ne reconstruit que ce qui a changé et déploie sur Cloudflare Pages, une nuit calme ne télécharge et ne déploie rienChaque nuitGitHub ActionsOpen datadu nouveau ?nouveau voteReconstruirejuste ce qui a changéDéployerCloudflare Pagesaucun voteNuit calmeni téléchargé ni déployé20 000 fichiers par déploiement,8 000+ votes livrés par blocs,le tout vérifié contre un budget.
  3. Séance

    App · entraînement · installable, hors ligne

    Un programme au poids du corps dessiné comme un manuel de gymnastique, une planche par mouvement. Il guide une séance de trente minutes, tient un journal et trace les courbes de progrès — installable, hors ligne, avec des rappels, et chaque chiffre gardé sur l’appareil.

    Entrée complèteOuvrir en ligne (s’ouvre dans un nouvel onglet)
    Dessin : un téléphone affichant une planche de mouvement d’une séance, marquée hors ligne et enregistrée sur cet appareilPLANCHE · MOUVEMENTPompesSérieReposEXERCICE SUIVANTHORS LIGNEchaque route répondSUR L’APPAREILchaque chiffre, rien qu’iciJOINTURES, PAS TRACÉS37 figures, chaînéesdepuis la hanche
    Dessiné pour ce registre, pas une capture
    Livré29 · IX · 2026

    Ce qui est livré

    1. Installable et entièrement hors ligne : un service worker Workbox écrit à la main met toute l’app en cache, et chaque route répond réseau coupé, séance en cours comprise.
    2. Des rappels sans serveur : une horloge dans l’app, les Notification Triggers là où ils existent, et le Periodic Background Sync qui lit le planning dans IndexedDB depuis le worker — et l’écran de réglages dit franchement ce que ce navigateur sait faire.
    3. Des graphiques de progression dessinés à la main en SVG et HTML : régularité comptée en semaines, volume par semaine, tour de taille et poids jamais sur un même axe, chacun parcourable par un input range natif invisible et doublé d’un tableau.
    4. Chaque chiffre reste sur l’appareil : une sauvegarde JSON le transporte ailleurs, et un profil spécimen généré à graine montre les graphiques pleins sans jamais toucher aux données du lecteur.
    5. Trente-sept figures animées dessinées à partir d’articulations, pas de tracés : l’interpolation est polaire et chaînée depuis la hanche, pour qu’aucun os ne s’étire en plein mouvement.
    Code source (s’ouvre dans un nouvel onglet)

    Mécanisme · zéro serveur, tout en cache sur l’appareil

    Schéma : dans l’appareil, la coque de l’app est précachée par un service worker et chaque chiffre vit dans IndexedDB ; le réseau est coupé et il n’y a pas de serveurCet appareilCoque de l’appprécachéeService workerWorkbox · rappelsIndexedDBchaque chiffreSans serveurréseau coupéSauvegarde JSONla seule sortie
  4. Analytics

    App · mesure d’audience · tableau de bord public

    Hono sur Cloudflare Workers, D1 et les Core Web Vitals, avec un tableau de bord public. Une ligne tient un chemin, un domaine référent, un pays, une langue, un thème et un type d’appareil, et il n’y a pas de bandeau de consentement : il n’y a rien à consentir.

    Ce siteTaverlaon-record

    Entrée complèteOuvrir en ligne (s’ouvre dans un nouvel onglet)
    Dessin : le tableau de bord public avec les pages vues, les Core Web Vitals et les quelques colonnes d’une ligne, à côté d’une fiche listant ce qui n’est jamais stockéPAGES VUESTableau de bord publicCORE WEB VITALSLCPINPCLSCHEMINRÉFÉRENTPAYSTHÈMEAPPAREIL/en/projectsgithub.comFRsombremobile/fr—BEclairordinateurJAMAIS STOCKÉcookieIPuser agentempreintehashTRACKER.JSmoins d’1 ko gzippéALIMENTÉ PAR CE SITE, TAVERLA ET ON-RECORDpas de bannière de consentement : rien à consentir
    Dessiné pour ce registre, pas une capture
    En ligne30 · IX · 2026

    Ce qui est livré

    1. Ni cookie, ni IP, ni user agent, ni empreinte, ni hash stockés : une ligne tient un chemin, un domaine référent, un pays, une langue, un thème et un type d’appareil.
    2. Pas de bandeau de consentement : il n’y a rien à consentir.
    3. Une page vue atteinte depuis une autre page du même site prolonge une visite ; tout le reste en commence une.
    4. tracker.js pèse moins de 1 ko compressé, suit la navigation des applications monopages, et ne tourne jamais sur localhost ni dans un navigateur automatisé.
    5. Ajouter ?analytics=off à une URL arrête de compter ce navigateur.
    Code source (s’ouvre dans un nouvel onglet)

    Mécanisme · trois apps envoient, un Worker écrit une ligne

    Schéma : ce site, Taverla et on-record exécutent chacun tracker.js, qui envoie les pages vues à un Worker Hono sur Cloudflare ; il écrit dans D1 une ligne de six champs et ne stocke jamais de cookie, d’IP, de user agent, d’empreinte ni de hash ; le tableau de bord public lit D1Ce sitetracker.jsTaverlatracker.json-recordtracker.jsUn WorkerHono · CloudflareD1 · une lignecheminhôte référentpayslanguethèmetype d’appareilTableau de bordpublic · ReactJamais stockécookie · IP · user agentempreinte · hash
  5. Scoreboard

    App · score en direct · salle de club

    Un tableau des scores en direct pour les clubs qui jouent sur plusieurs tables à la fois. Quatre écrans dans le navigateur — le grand écran, la console d’arbitre, la console d’organisation et la vue spectateur — partagent un Durable Object par événement sur l’offre gratuite de Cloudflare, sans rien à installer.

    Entrée complèteOuvrir en ligne (s’ouvre dans un nouvel onglet)
    En ligne3 · X · 2026

    Ce qui est livré

    1. Chaque arbitre compte son match depuis l’appareil qu’il a sous la main, et tous les matchs en cours s’affichent sur un seul grand écran au fond de la salle.
    2. Un Durable Object par événement garde la suite ordonnée des points dans son propre stockage SQLite et la diffuse en WebSocket.
    3. Les points comptés hors ligne attendent en file et repartent à la reconnexion, et une erreur s’annule d’un geste.
    4. Score, service et durées se déduisent tous des événements : l’organisateur corrige un score faux ou déplace un match sur une autre table en direct.
    5. Le tennis de table est le premier règlement ; les règles de score se branchent, d’autres sports peuvent suivre.
    Code source (s’ouvre dans un nouvel onglet)
  6. adrienlacourpaille.dev

    Ce site · en cours

    Le registre que vous lisez. React 19, prérendu par langue, en anglais et en français, clair et sombre sans flash, des primitives accessibles signées react-aria, et un score Lighthouse vérifié en CI.

    les 11 paquets maison

    Analytics

    Lighthouse
    Vérifié en CI
    Langues
    en · fr
    Hébergement
    Cloudflare Pages
    En cours
    1. @adrienlcp/react-router (s’ouvre dans un nouvel onglet)

      Le fournisseur de routeur que prend chaque app.

      0.1.1Utilisé par TaverlaUtilisé par on-recordUtilisé par SéancePas utilisé par AnalyticsPas utilisé par ScoreboardUtilisé par Ce siteLivré
    2. @adrienlcp/i18n (s’ouvre dans un nouvel onglet)

      Traduit, et sait dès la compilation ce que chaque message attend.

      0.3.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsPas utilisé par ScoreboardUtilisé par Ce siteLivré
    3. @adrienlcp/theme-preference (s’ouvre dans un nouvel onglet)

      Garde le thème choisi sans flash, jusqu’à la barre du téléphone.

      0.3.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéancePas utilisé par AnalyticsPas utilisé par ScoreboardUtilisé par Ce siteLivré
    4. @adrienlcp/browser (s’ouvre dans un nouvel onglet)

      Copie dans le presse-papiers même en HTTP simple, où l’API Clipboard n’existe pas.

      0.1.1Utilisé par TaverlaUtilisé par on-recordUtilisé par SéancePas utilisé par AnalyticsPas utilisé par ScoreboardUtilisé par Ce siteLivré
    5. @adrienlcp/react (s’ouvre dans un nouvel onglet)

      Les utilitaires de contexte dont part chaque app React.

      0.3.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    6. @adrienlcp/react-aria (s’ouvre dans un nouvel onglet)

      L’anneau de focus et la composition de classes sur react-aria-components.

      0.1.0Utilisé par TaverlaUtilisé par on-recordPas utilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    7. @adrienlcp/styles (s’ouvre dans un nouvel onglet)

      Le reset et les styles partagés dont part chaque projet.

      0.5.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    8. @adrienlcp/result (s’ouvre dans un nouvel onglet)

      Dit si quelque chose a marché, sans exception et sans null.

      0.1.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    9. @adrienlcp/safe-storage (s’ouvre dans un nouvel onglet)

      Ôte les exceptions de localStorage et renvoie un Result à la place.

      0.1.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    10. @adrienlcp/tsconfig (s’ouvre dans un nouvel onglet)

      Les réglages du compilateur qu’étend chaque projet.

      0.1.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré
    11. @adrienlcp/biome-config (s’ouvre dans un nouvel onglet)

      Les réglages du linter et du formateur qu’étend chaque projet.

      0.1.0Utilisé par TaverlaUtilisé par on-recordUtilisé par SéanceUtilisé par AnalyticsUtilisé par ScoreboardUtilisé par Ce siteLivré

Depuis 2023, je suis au travail le seul développeur d’une plateforme multi-écrans en production. Je tiens à une architecture saine, des monorepos aux API typées de bout en bout, à l’accessibilité et aux tests, et je garde mes projets sur les dernières versions de leur écosystème.

Votre équipe, 2026

Je cherche mon prochain poste. Écrivez-moi, ou prenez le CV : un mis en page, et un sobre pour les logiciels de recrutement.