{"id":584,"date":"2026-01-01T13:00:00","date_gmt":"2026-01-01T12:00:00","guid":{"rendered":"https:\/\/portfolio.cousseaujimmy.fr\/projets\/lamaquest\/"},"modified":"2026-09-11T15:40:58","modified_gmt":"2026-09-11T13:40:58","slug":"lamaquest","status":"publish","type":"projet","link":"https:\/\/portfolio.cousseaujimmy.fr\/en\/projets\/lamaquest\/","title":{"rendered":"LamaQuest"},"content":{"rendered":"\n<h2 class=\"wp-block-heading jcp-reveal\">The game<\/h2>\n\n\n\n<p class=\"jcp-reveal wp-block-paragraph\">The host places points on a map, one question per point, and starts a game with a code. Players join from their phone, no install, walk to the points (GPS validation), answer and follow the live leaderboard \u2014 with <strong>powers<\/strong> to spend against each other.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-4 is-cropped jcp-reveal is-style-phones wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-jcp-shot\"><img decoding=\"async\" width=\"804\" height=\"1748\" data-id=\"566\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte.webp\" alt=\"\" class=\"wp-image-566\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte.webp 804w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-138x300.webp 138w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-471x1024.webp 471w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-768x1670.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-706x1536.webp 706w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-414x900.webp 414w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-carte-552x1200.webp 552w\" sizes=\"(max-width: 804px) 100vw, 804px\" \/><\/figure>\n\n\n<figure class=\"wp-block-image size-jcp-shot\"><img decoding=\"async\" width=\"804\" height=\"1748\" data-id=\"570\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question.webp\" alt=\"\" class=\"wp-image-570\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question.webp 804w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-138x300.webp 138w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-471x1024.webp 471w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-768x1670.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-706x1536.webp 706w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-414x900.webp 414w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-question-552x1200.webp 552w\" sizes=\"(max-width: 804px) 100vw, 804px\" \/><\/figure>\n\n\n<figure class=\"wp-block-image size-jcp-shot\"><img decoding=\"async\" width=\"804\" height=\"1748\" data-id=\"567\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement.webp\" alt=\"\" class=\"wp-image-567\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement.webp 804w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-138x300.webp 138w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-471x1024.webp 471w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-768x1670.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-706x1536.webp 706w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-414x900.webp 414w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-classement-552x1200.webp 552w\" sizes=\"(max-width: 804px) 100vw, 804px\" \/><\/figure>\n\n\n<figure class=\"wp-block-image size-jcp-shot\"><img decoding=\"async\" width=\"804\" height=\"1748\" data-id=\"569\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs.webp\" alt=\"\" class=\"wp-image-569\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs.webp 804w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-138x300.webp 138w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-471x1024.webp 471w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-768x1670.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-706x1536.webp 706w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-414x900.webp 414w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-pouvoirs-552x1200.webp 552w\" sizes=\"(max-width: 804px) 100vw, 804px\" \/><\/figure>\n<\/figure>\n\n\n\n<h2 class=\"wp-block-heading jcp-reveal\">Under the hood<\/h2>\n\n\n\n<ul class=\"wp-block-list jcp-reveal\">\n\n<li><strong>Vue 3 + Pinia + MapLibre<\/strong>, self-hosted Protomaps tiles: no API key, no quota.<\/li>\n\n\n<li><strong>Bun + Hono + Prisma + PostgreSQL<\/strong>, one WebSocket per game, proximity computed server-side.<\/li>\n\n\n<li><strong>Stripe<\/strong> (credits, webhooks, VAT) \u2014 only hosts pay.<\/li>\n\n\n<li><strong>Self-hosted AI<\/strong> (Ollama) to generate quizzes, and an <strong>MCP<\/strong> server.<\/li>\n\n\n<li>Unit tests, Cucumber e2e, load tests; Docker; deployment through <code>docker save | ssh docker load<\/code>.<\/li>\n\n<\/ul>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-2 is-cropped jcp-reveal wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-jcp-card\"><img decoding=\"async\" width=\"1920\" height=\"1200\" data-id=\"568\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard.webp\" alt=\"\" class=\"wp-image-568\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard.webp 1920w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-300x188.webp 300w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-1024x640.webp 1024w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-768x480.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-1536x960.webp 1536w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-1440x900.webp 1440w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-dashboard-800x500.webp 800w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/figure>\n\n\n<figure class=\"wp-block-image size-jcp-card\"><img decoding=\"async\" width=\"1920\" height=\"1200\" data-id=\"571\" src=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur.webp\" alt=\"\" class=\"wp-image-571\" srcset=\"https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur.webp 1920w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-300x188.webp 300w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-1024x640.webp 1024w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-768x480.webp 768w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-1536x960.webp 1536w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-1440x900.webp 1440w, https:\/\/portfolio.cousseaujimmy.fr\/wp-content\/uploads\/2026\/09\/app-superviseur-800x500.webp 800w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/figure>\n<\/figure>\n\n\n\n<h2 class=\"wp-block-heading jcp-reveal\">What I take away<\/h2>\n\n\n\n<p class=\"jcp-reveal wp-block-paragraph\">A product is not done when the code compiles, but when someone else can use it, pay for it and deploy it without me. The marketing site is <a href=\"https:\/\/portfolio.cousseaujimmy.fr\/projets\/lamaquest-site\/\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Real-time multiplayer GPS treasure hunt, designed, built and operated solo. In production.<\/p>\n","protected":false},"featured_media":578,"menu_order":0,"template":"","meta":{"_jcp_tagline":"A multiplayer GPS treasure hunt, from idea to production: real time, offline maps, payments, AI.","_jcp_role":"Design, development, operations \u2014 solo","_jcp_org":"lamaquest.com","_jcp_period":"2025 \u2192 2026","_jcp_sort":"2026-09","_jcp_repo":"https:\/\/forgejo.cousseaujimmy.fr\/Jimmyrtille\/lamaquest","_jcp_live":"https:\/\/app.lamaquest.com","_jcp_status":"prod","_jcp_featured":true,"_jcp_stats":"[{\"value\": \"72 k\", \"label\": \"[:fr]lignes de code[:en]lines of code[:es]l\u00edneas de c\u00f3digo[:]\"}, {\"value\": \"3\", \"label\": \"[:fr]langues[:en]languages[:es]idiomas[:]\"}, {\"value\": \"1\", \"label\": \"[:fr]WebSocket par partie[:en]WebSocket per game[:es]WebSocket por partida[:]\"}]","_jcp_accent":"#f16e21","footnotes":""},"projet-type":[57],"stack":[68,105,69,102,99,103,106,93,94,80,113,66,65,97],"class_list":["post-584","projet","type-projet","status-publish","has-post-thumbnail","hentry","projet-type-produit","stack-bun","stack-docker","stack-hono","stack-llm","stack-maplibre","stack-mcp","stack-nginx","stack-postgresql","stack-prisma","stack-stripe","stack-tests","stack-typescript","stack-vue","stack-websocket"],"_links":{"self":[{"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/projet\/584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/projet"}],"about":[{"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/types\/projet"}],"version-history":[{"count":7,"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/projet\/584\/revisions"}],"predecessor-version":[{"id":700,"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/projet\/584\/revisions\/700"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/media\/578"}],"wp:attachment":[{"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/media?parent=584"}],"wp:term":[{"taxonomy":"projet-type","embeddable":true,"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/projet-type?post=584"},{"taxonomy":"stack","embeddable":true,"href":"https:\/\/portfolio.cousseaujimmy.fr\/en\/wp-json\/wp\/v2\/stack?post=584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}