<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ace Jogos do Rei</title>
    <description>The latest articles on DEV Community by Ace Jogos do Rei (@ace_rei).</description>
    <link>https://dev.to/ace_rei</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3864416%2F8f839146-2889-41af-a649-f4271aa3d3f0.png</url>
      <title>DEV Community: Ace Jogos do Rei</title>
      <link>https://dev.to/ace_rei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ace_rei"/>
    <language>en</language>
    <item>
      <title>Mobile-First for 60+ Year Olds — What We Learned Building for Senior Gamers</title>
      <dc:creator>Ace Jogos do Rei</dc:creator>
      <pubDate>Wed, 01 Jul 2026 13:09:15 +0000</pubDate>
      <link>https://dev.to/ace_rei/mobile-first-for-60-year-olds-what-we-learned-building-for-senior-gamers-1o0</link>
      <guid>https://dev.to/ace_rei/mobile-first-for-60-year-olds-what-we-learned-building-for-senior-gamers-1o0</guid>
      <description>&lt;p&gt;Most "mobile-first" advice is written for an imaginary user: a 28-year-old with perfect eyesight, a flagship phone, fast fingers, and a fiber connection. That user does not represent the audience for the platform I work on. A large share of the people playing card games like Buraco, Canastra, and Tranca on &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt; are 60 years and older. The platform has been around since 2010 and has grown to 3M+ registered players, and a meaningful chunk of that base did not grow up with touchscreens.&lt;/p&gt;

&lt;p&gt;Building for that audience forces you to unlearn a lot of habits. Here are the constraints we kept running into and the tradeoffs we made.&lt;/p&gt;

&lt;h2&gt;
  
  
  Touch targets are not a "nice to have"
&lt;/h2&gt;

&lt;p&gt;The WCAG guidance of a 44×44px minimum touch target is treated as a floor by most teams and quietly ignored in dense UIs. For older users it's closer to a hard requirement, and honestly 44px is on the small side. Reduced fine-motor precision and, in some cases, mild tremor mean that a mistap isn't a minor annoyance — it's a wrong card played in a live match, which feels catastrophic to the player.&lt;/p&gt;

&lt;p&gt;Concrete things that helped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generous hit areas that extend beyond the visible control. The tappable region can be larger than what the eye sees, and that padding absorbs imprecise taps.&lt;/li&gt;
&lt;li&gt;Spacing between interactive elements so adjacent taps don't fire the wrong action. In a hand of cards this is the hard part — cards naturally overlap. We lean on fanning out the active card and enlarging the one under the finger rather than cramming more cards into the same width.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No destructive action one tap away from a common action.&lt;/strong&gt; "Leave table" next to "Play card" is a trap. Confirmation dialogs are annoying for power users but they save older players from actions they didn't intend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Font size, contrast, and the zoom problem
&lt;/h2&gt;

&lt;p&gt;Older eyes need larger type and higher contrast, and this is where a lot of well-meaning responsive design breaks.&lt;/p&gt;

&lt;p&gt;The first instinct is to bump base font sizes. Good. But the second-order effect is that many senior users &lt;em&gt;also&lt;/em&gt; set their OS or browser zoom to 150–200% on top of your already-large type. If your layout assumes a fixed viewport and uses absolute positioning or &lt;code&gt;overflow: hidden&lt;/code&gt; to look tidy, that zoom shatters it — buttons disappear off-screen, text clips, modals become unusable.&lt;/p&gt;

&lt;p&gt;Lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design so the layout survives 200% zoom. Use relative units (&lt;code&gt;rem&lt;/code&gt;/&lt;code&gt;em&lt;/code&gt;), let containers grow, and test with the browser zoomed rather than only with responsive dev-tools breakpoints.&lt;/li&gt;
&lt;li&gt;Don't ship contrast that only passes on your calibrated monitor. Older displays, glare, and age-related contrast sensitivity loss all eat into your margin. We aim comfortably past the WCAG AA 4.5:1 ratio for body text rather than sitting right on it.&lt;/li&gt;
&lt;li&gt;Avoid thin/light font weights for anything the user must read. They look elegant and they're hard to read.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The connection you don't have
&lt;/h2&gt;

&lt;p&gt;The "mobile-first" persona assumes a fast, stable connection. A big portion of real traffic is on older Android devices over spotty mobile networks, sometimes on a phone that's four or five years old with limited RAM. That reframes a lot of decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ship less JavaScript. A heavy SPA that's snappy on a MacBook can jank badly on a budget Android from 2019. Every KB of parse/execute time is felt. We're aggressive about not pulling in a framework where plain HTML, CSS, and a bit of vanilla JS will do — the same philosophy behind our public &lt;a href="https://jogosdorei.github.io/glossario-buraco/" rel="noopener noreferrer"&gt;card-game glossary&lt;/a&gt;, which is static HTML precisely so it loads instantly on weak devices.&lt;/li&gt;
&lt;li&gt;Assume reconnection is normal, not exceptional. In a real-time card game the network &lt;em&gt;will&lt;/em&gt; drop mid-match. The interesting UX work isn't preventing disconnects (you can't) — it's making reconnection graceful so the player rejoins the table where they left off instead of being kicked and losing the game. For an older player, being dropped from a game they were winning is the kind of frustration that makes them churn.&lt;/li&gt;
&lt;li&gt;Optimistic UI has to be handled carefully. Showing an action as "done" before the server confirms feels fast, but if it later has to roll back, a confused senior player reads it as a bug or as cheating. We prefer honest, immediate feedback ("sending…") over an optimistic state that might reverse.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Copy and iconography
&lt;/h2&gt;

&lt;p&gt;A pattern we've had to correct repeatedly: designers love icon-only buttons. A gear, a hamburger, three dots. For a 30-year-old these are learned universal symbols. For a 65-year-old who came to the internet later, many of them are not obvious at all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pair icons with text labels wherever space allows. "☰ Menu" beats "☰".&lt;/li&gt;
&lt;li&gt;Prefer plain, literal wording over clever product-speak. "Sair da mesa" (Leave table), not "Encerrar sessão".&lt;/li&gt;
&lt;li&gt;Be careful with gestures. Swipe-to-do-X and long-press menus are effectively invisible to users who don't know to try them. Anything important needs a visible, tappable path.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where "mobile-first" and "senior-first" actually conflict
&lt;/h2&gt;

&lt;p&gt;It's worth being honest: these two goals pull against each other sometimes.&lt;/p&gt;

&lt;p&gt;Mobile-first pushes you toward compact, gesture-driven, minimal-chrome interfaces. Senior-first pushes toward larger elements, explicit labels, visible controls, and confirmations. You cannot fully satisfy both on a small screen.&lt;/p&gt;

&lt;p&gt;Our resolution is that the &lt;em&gt;desktop&lt;/em&gt; experience remains a first-class citizen rather than an afterthought — a genuinely large share of our older players are on desktop, where screen real estate lets us give elements the size and spacing they need without cramming. That runs against the industry reflex to treat desktop as a scaled-up phone. For this audience, "mobile-first" is a technique for performance and resilience on weak devices, not a mandate to shove everything into a 360px column.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell another team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test with actual older users, not a simulator.&lt;/strong&gt; Watching a 70-year-old try to play one hand teaches you more than a dozen accessibility lint passes. You'll see the mistaps, the squinting, the abandoned gestures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat undo/confirm as core UX, not friction.&lt;/strong&gt; For this audience, reversibility beats speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget for the low end.&lt;/strong&gt; Performance is accessibility. A slow, janky page excludes older users on old hardware just as surely as poor contrast does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't hide function behind cleverness.&lt;/strong&gt; Visible, labeled, generously-sized, and forgiving beats sleek every time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is exotic — it's mostly WCAG fundamentals plus taking your real audience seriously instead of the imaginary median user. But the discipline of building for people who are 60+ and on modest hardware has a nice side effect: it makes the product better for &lt;em&gt;everyone&lt;/em&gt;. Larger targets, clearer copy, faster loads, and graceful reconnection are things a 28-year-old on a flagship phone appreciates too — they just won't churn if you get them wrong.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>a11y</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Building a Searchable Card-Game Glossary with Static HTML, Lightweight JS and SEO Pages</title>
      <dc:creator>Ace Jogos do Rei</dc:creator>
      <pubDate>Tue, 21 Apr 2026 12:37:03 +0000</pubDate>
      <link>https://dev.to/ace_rei/building-a-searchable-card-game-glossary-with-static-html-lightweight-js-and-seo-pages-25hm</link>
      <guid>https://dev.to/ace_rei/building-a-searchable-card-game-glossary-with-static-html-lightweight-js-and-seo-pages-25hm</guid>
      <description>&lt;h1&gt;
  
  
  Building a Searchable Card-Game Glossary with Static HTML, Lightweight JS and SEO Pages
&lt;/h1&gt;

&lt;p&gt;At &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;, we serve a very specific audience: Brazilian players who care about traditional card games like Buraco, Tranca and Truco. That audience has real search demand, but it also has a vocabulary problem.&lt;/p&gt;

&lt;p&gt;Players search for terms like &lt;strong&gt;morto&lt;/strong&gt;, &lt;strong&gt;manilha&lt;/strong&gt;, &lt;strong&gt;canastra limpa&lt;/strong&gt;, &lt;strong&gt;3 preto&lt;/strong&gt; and &lt;strong&gt;mão de onze&lt;/strong&gt;. If you don't explain those terms clearly, you lose both search traffic and user trust.&lt;/p&gt;

&lt;p&gt;So we built a searchable glossary page as a lightweight static site, with a simple goal: make the terminology easy to understand and easy to index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constraints
&lt;/h2&gt;

&lt;p&gt;We did not need a complex frontend stack for this.&lt;/p&gt;

&lt;p&gt;The requirements were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fast load on desktop and low-end mobile devices&lt;/li&gt;
&lt;li&gt;indexable pages for glossary terms&lt;/li&gt;
&lt;li&gt;simple client-side search&lt;/li&gt;
&lt;li&gt;internal links back to the main platform and rules pages&lt;/li&gt;
&lt;li&gt;easy maintenance by a small team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That pushed us toward a very simple architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;The glossary was built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;static HTML&lt;/li&gt;
&lt;li&gt;small amounts of vanilla JavaScript&lt;/li&gt;
&lt;li&gt;semantic headings and internal links&lt;/li&gt;
&lt;li&gt;sitemap and robots for crawlability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Public examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Main platform: &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Glossary hub: &lt;a href="https://jogosdorei.github.io/glossario-buraco/" rel="noopener noreferrer"&gt;glossario-buraco on GitHub Pages&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why static was the right choice
&lt;/h2&gt;

&lt;p&gt;A glossary is mostly a content retrieval problem, not an application state problem.&lt;/p&gt;

&lt;p&gt;That means the best tradeoff was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pre-render the page&lt;/li&gt;
&lt;li&gt;keep markup semantic&lt;/li&gt;
&lt;li&gt;use lightweight client-side filtering for UX&lt;/li&gt;
&lt;li&gt;avoid framework overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Static delivery gave us predictable performance, zero runtime complexity for the glossary itself and cleaner crawl paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search experience
&lt;/h2&gt;

&lt;p&gt;We added a client-side search box so users can type a term like &lt;code&gt;morto&lt;/code&gt; or &lt;code&gt;manilha&lt;/code&gt; and quickly find the relevant card.&lt;/p&gt;

&lt;p&gt;This is intentionally simple. The page does not need fuzzy ranking, remote queries or a heavy component tree. It just needs to reduce friction.&lt;/p&gt;

&lt;p&gt;For informational surfaces like this, the engineering question is usually not “how do we make this more sophisticated?”&lt;/p&gt;

&lt;p&gt;It is “what is the smallest system that solves the problem reliably?”&lt;/p&gt;

&lt;h2&gt;
  
  
  SEO decisions that mattered
&lt;/h2&gt;

&lt;p&gt;The useful parts were not fancy.&lt;/p&gt;

&lt;p&gt;They were basic things done consistently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;descriptive title and meta description&lt;/li&gt;
&lt;li&gt;canonical URL&lt;/li&gt;
&lt;li&gt;internal links back to the product and rules pages&lt;/li&gt;
&lt;li&gt;content grouped by game concepts&lt;/li&gt;
&lt;li&gt;readable copy written around the actual language players use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also added supporting files such as sitemap/robots and expanded navigation so related pages reinforce each other instead of competing blindly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product lesson
&lt;/h2&gt;

&lt;p&gt;When you run a niche product, terminology is part of onboarding.&lt;/p&gt;

&lt;p&gt;A glossary is not just an SEO artifact. It also reduces support friction and helps new players understand game rules faster.&lt;/p&gt;

&lt;p&gt;That was the main reason this project was worth shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;If your users search for domain-specific terms, a small static glossary can be one of the highest-leverage content/engineering hybrids you can build.&lt;/p&gt;

&lt;p&gt;Keep it fast. Keep it indexable. Keep it useful.&lt;/p&gt;

&lt;p&gt;And only add complexity if the problem really demands it.&lt;/p&gt;




&lt;p&gt;If you want to see the public examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jogosdorei.github.io/glossario-buraco/" rel="noopener noreferrer"&gt;Glossary project on GitHub Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Como construí um glossário de jogos de cartas brasileiros com HTML e JavaScript puro</title>
      <dc:creator>Ace Jogos do Rei</dc:creator>
      <pubDate>Sat, 18 Apr 2026 11:53:39 +0000</pubDate>
      <link>https://dev.to/ace_rei/como-construi-um-glossario-de-jogos-de-cartas-brasileiros-com-html-e-javascript-puro-15eo</link>
      <guid>https://dev.to/ace_rei/como-construi-um-glossario-de-jogos-de-cartas-brasileiros-com-html-e-javascript-puro-15eo</guid>
      <description>&lt;h1&gt;
  
  
  Como construí um glossário de jogos de cartas brasileiros com HTML e JavaScript puro
&lt;/h1&gt;

&lt;p&gt;Se você já jogou Buraco, Tranca ou Truco, sabe que cada jogo tem um vocabulário próprio. Morto, canastra limpa, manilha, 3 preto… são termos que confundem até jogadores experientes.&lt;/p&gt;

&lt;p&gt;No &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;, a maior plataforma de jogos de cartas do Brasil, percebemos que nossos jogadores precisavam de uma referência clara e acessível. A solução: um glossário público, totalmente estático, hospedado no GitHub Pages, sem frameworks, sem build steps — só HTML, CSS e JavaScript vanilla.&lt;/p&gt;

&lt;h2&gt;
  
  
  O desafio
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Precisão&lt;/strong&gt;: o conteúdo tinha que refletir fielmente as regras oficiais de cada modalidade (Buraco Aberto, Buraco Fechado, STBL, Tranca, Truco).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acessibilidade&lt;/strong&gt;: o site precisava funcionar bem em qualquer dispositivo, inclusive para nosso público principal (jogadores 60+, muitos em desktop).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manutenção simples&lt;/strong&gt;: queríamos que qualquer pessoa da equipe pudesse editar os termos sem precisar de conhecimento técnico avançado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO&lt;/strong&gt;: o glossário deveria aparecer em buscas por termos como "o que é morto no buraco", "regras da tranca", "como jogar truco paulista".&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A solução técnica
&lt;/h2&gt;

&lt;p&gt;Optamos por uma stack minimalista:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 semântico&lt;/strong&gt; – cada termo é um &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; com &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; e &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, facilitando a indexação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Grid/Flexbox&lt;/strong&gt; – layout responsivo que se adapta de mobile a desktop sem media queries complexas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript vanilla&lt;/strong&gt; – uma função de busca client-side de ~20 linhas que filtra os termos em tempo real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Pages&lt;/strong&gt; – hospedagem gratuita, com deploy automático via &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplo do código de busca
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;filtrarTermos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.term-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-termo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bônus: página comparativa
&lt;/h2&gt;

&lt;p&gt;Além dos glossários individuais, criamos uma &lt;a href="https://jogosdorei.github.io/glossario-buraco/comparativo.html" rel="noopener noreferrer"&gt;página comparativa&lt;/a&gt; que coloca lado a lado as cinco modalidades disponíveis na plataforma. A tabela mostra diferenças como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Número de cartas&lt;/li&gt;
&lt;li&gt;Presença de curingão&lt;/li&gt;
&lt;li&gt;Permissão de trincas&lt;/li&gt;
&lt;li&gt;Regra para bater (ganhar a rodada)&lt;/li&gt;
&lt;li&gt;Complexidade estratégica&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa página é especialmente útil para jogadores que querem experimentar uma nova modalidade e precisam entender rapidamente o que muda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resultados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Indexação rápida&lt;/strong&gt;: o site apareceu nos resultados do Google em menos de 48 horas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback positivo&lt;/strong&gt;: jogadores elogiaram a clareza e a facilidade de consulta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baixa manutenção&lt;/strong&gt;: desde o lançamento, fizemos apenas duas pequenas correções (typos).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lições aprendidas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JS ainda é poderoso&lt;/strong&gt; – para projetos de conteúdo estático, frameworks são overkill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO orgânico ama HTML semântico&lt;/strong&gt; – usar &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; para tabelas comparativas gerou rich snippets automaticamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance é feature&lt;/strong&gt; – o site carrega em &amp;lt;1s mesmo em conexões lentas, porque não há nada além de arquivos estáticos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentação é produto&lt;/strong&gt; – um glossário bem feito reduz suporte (menos perguntas sobre regras) e engaja a comunidade.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O código está aberto
&lt;/h2&gt;

&lt;p&gt;Todo o projeto está disponível no GitHub: &lt;a href="https://github.com/jogosdorei/glossario-buraco" rel="noopener noreferrer"&gt;jogosdorei/glossario-buraco&lt;/a&gt;. Sinta-se à vontade para usar como base para seus próprios glossários ou sites de referência.&lt;/p&gt;

&lt;h2&gt;
  
  
  E você? Já construiu algo similar?
&lt;/h2&gt;

&lt;p&gt;Conta aí nos comentários se você já fez algum projeto de documentação técnica com stack minimalista. Quais foram os desafios e acertos?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Este artigo foi escrito pelo Ace, personagem do &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;, plataforma com mais de 3 milhões de jogadores de cartas online no Brasil.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>html</category>
      <category>githubpages</category>
    </item>
    <item>
      <title>How We Built a Card Game Platform with 3 Million Players (and What We Learned)</title>
      <dc:creator>Ace Jogos do Rei</dc:creator>
      <pubDate>Mon, 06 Apr 2026 18:42:17 +0000</pubDate>
      <link>https://dev.to/ace_rei/how-we-built-a-card-game-platform-with-3-million-players-and-what-we-learned-mj0</link>
      <guid>https://dev.to/ace_rei/how-we-built-a-card-game-platform-with-3-million-players-and-what-we-learned-mj0</guid>
      <description>&lt;h1&gt;
  
  
  How We Built a Card Game Platform with 3 Million Players (and What We Learned)
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A founder's tech perspective on scaling an online card game in Brazil&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Building a niche gaming platform that lasts 15 years and reaches 3 million players doesn't happen by accident. At &lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;Jogos do Rei&lt;/a&gt;, we've been running Brazil's largest online card games platform since 2010 — and I want to share some of what we learned along the way.&lt;/p&gt;

&lt;p&gt;This isn't a story about hockey-stick growth or VC funding. It's about building something deeply rooted in culture, keeping the servers alive, and not alienating the players who trust you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;Jogos do Rei is a platform for traditional Brazilian card games: &lt;strong&gt;Buraco&lt;/strong&gt; (known as Canastra in some regions), &lt;strong&gt;Tranca&lt;/strong&gt;, &lt;strong&gt;Truco&lt;/strong&gt;, and &lt;strong&gt;STBL&lt;/strong&gt; (Buraco Fechado). These are games most Brazilians grew up watching their grandparents play. Our job was to bring them online, keep them social, and make them feel authentic.&lt;/p&gt;

&lt;p&gt;By the numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3+ million registered players&lt;/li&gt;
&lt;li&gt;Games running 24/7 since 2010&lt;/li&gt;
&lt;li&gt;Daily tournaments with real opponents (no bots in game rooms)&lt;/li&gt;
&lt;li&gt;Weekly leagues with ranking systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Real Challenge: Real-Time Multi-Player State
&lt;/h2&gt;

&lt;p&gt;Card games look simple from the outside. But managing real-time multiplayer state for a game like Buraco is surprisingly tricky.&lt;/p&gt;

&lt;h3&gt;
  
  
  The State Problem
&lt;/h3&gt;

&lt;p&gt;At any point in a Buraco hand, you need to track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each player's hand (private)&lt;/li&gt;
&lt;li&gt;The table (public plays visible to all)&lt;/li&gt;
&lt;li&gt;The discard pile (public, ordered)&lt;/li&gt;
&lt;li&gt;Two "mortos" (hidden piles of 11 cards each, revealed when a player goes out)&lt;/li&gt;
&lt;li&gt;Round scores and game scores&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game has complex actions: drawing from the deck, picking up the entire discard pile (only valid with certain conditions), laying down melds, extending existing melds, and going out in three different ways (direct, indirect, and final).&lt;/p&gt;

&lt;p&gt;All of this needs to be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validated server-side (never trust the client)&lt;/li&gt;
&lt;li&gt;Transmitted in near-real-time to all players at the table&lt;/li&gt;
&lt;li&gt;Kept in sync even when connections drop&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Our Approach
&lt;/h3&gt;

&lt;p&gt;We kept a canonical authoritative game state on the server. Clients send actions (not state updates). The server validates, applies the action, and broadcasts the new state delta.&lt;/p&gt;

&lt;p&gt;This "server is king" model means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No cheating via client manipulation&lt;/li&gt;
&lt;li&gt;Clean reconnect logic (request full state on reconnect)&lt;/li&gt;
&lt;li&gt;Easier to audit for anti-cheat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is latency sensitivity. For a card game, we found that &lt;strong&gt;under 300ms round-trip is fine&lt;/strong&gt;. Players don't feel rubber-band effects the way they do in action games.&lt;/p&gt;




&lt;h2&gt;
  
  
  Matchmaking: The Hidden Hard Problem
&lt;/h2&gt;

&lt;p&gt;When you have 3 million registered players but only a fraction online at any moment, matchmaking becomes critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Peaks and Valleys Problem
&lt;/h3&gt;

&lt;p&gt;Brazilian players are concentrated in specific timezone windows: lunch (12–14h BRT) and evening (20–23h BRT). Outside those peaks, finding 4 players for a Buraco table can take time.&lt;/p&gt;

&lt;p&gt;Our solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tiered waiting:&lt;/strong&gt; Short queue timeout → downgrade table requirements (e.g., allow cross-skill-level match)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lobby visibility:&lt;/strong&gt; Show players waiting in lobbies so others feel encouraged to join&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily tournaments:&lt;/strong&gt; Pre-scheduled times aggregate players, solving the coordination problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rating Systems for Card Games
&lt;/h3&gt;

&lt;p&gt;Standard Elo works reasonably well for 1v1. For 2v2 (which Buraco supports), we adapted it with team-based rating adjustments. The key insight: &lt;strong&gt;in card games, luck variance is high&lt;/strong&gt;. A rating system that moves too fast produces frustration; one that moves too slow feels unrewarding.&lt;/p&gt;

&lt;p&gt;We use a dampened Elo where K-factor decreases as player count grows, and we separate tournament ratings from casual ratings.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Social Layer is Not Optional
&lt;/h2&gt;

&lt;p&gt;Card games in Brazil are deeply social. Buraco at the club is as much about conversation as the cards. When we stripped that out early on, retention suffered.&lt;/p&gt;

&lt;p&gt;What we added over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-game chat&lt;/strong&gt; (with moderation — this is crucial)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent player profiles&lt;/strong&gt; with statistics and ranking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;League system&lt;/strong&gt; — weekly competitions that create regular engagement loops&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tables with names&lt;/strong&gt; — players can name their tables, creating regulars&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lesson: &lt;strong&gt;if you're building a multiplayer casual game, the social graph is the product&lt;/strong&gt;, not the game itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mobile vs Web: Still Not Solved
&lt;/h2&gt;

&lt;p&gt;Our player base skews 40–65 years old. That changes everything about your mobile strategy.&lt;/p&gt;

&lt;p&gt;Counterintuitive finding: &lt;strong&gt;older users often prefer desktop web&lt;/strong&gt;. They have larger screens, are comfortable with browsers, and are wary of installing apps.&lt;/p&gt;

&lt;p&gt;But mobile is growing, especially Android on budget devices. Our Android app (&lt;a href="https://play.google.com/store/apps/details?id=br.com.iterasoft.buraco" rel="noopener noreferrer"&gt;available on Play Store&lt;/a&gt;) required significant work to run well on 3–4 year old mid-range devices with 2GB RAM.&lt;/p&gt;

&lt;p&gt;Key optimizations for low-end Android:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lazy-load non-critical assets&lt;/li&gt;
&lt;li&gt;Minimal JS bundle (this is a card game, not a 3D shooter)&lt;/li&gt;
&lt;li&gt;Aggressive caching of card and table assets&lt;/li&gt;
&lt;li&gt;Graceful degradation of animations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Moderation at Scale: The Unglamorous Work
&lt;/h2&gt;

&lt;p&gt;3 million players means a meaningful percentage will behave badly. Buraco has a "no hints to partner" rule that's impossible to auto-enforce (it's a social contract, not a technical constraint). &lt;/p&gt;

&lt;p&gt;What we can enforce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abusive chat (filter + report system)&lt;/li&gt;
&lt;li&gt;AFK/abandonment (timeout system with automatic play)&lt;/li&gt;
&lt;li&gt;Collusion patterns (statistical anomaly detection on team win rates)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We give players a "Denunciar Abuso" (Report Abuse) button on every player avatar. Reports feed a moderation queue. The community self-polices surprisingly well when the reporting mechanism is visible and responsive.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We'd Do Differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build the API-first sooner.&lt;/strong&gt; We had a tightly coupled frontend/backend for years. Decoupling enabled mobile and new features much faster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analytics from day one.&lt;/strong&gt; We flew blind for too long. We didn't know which game modes had best retention until we measured properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Invest in moderation tools earlier.&lt;/strong&gt; A toxic player can ruin tables for dozens of others. The social experience is the moat — protect it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document the game rules publicly.&lt;/strong&gt; We eventually built comprehensive rules pages (like our &lt;a href="https://www.jogosdorei.com.br/regras-buraco.php" rel="noopener noreferrer"&gt;buraco rules&lt;/a&gt;) — this drives SEO and reduces support tickets.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Long Game
&lt;/h2&gt;

&lt;p&gt;Building a platform for traditional games means your players are loyal but not forgiving of regression. They've been playing Buraco for 40 years. They know when your implementation is wrong.&lt;/p&gt;

&lt;p&gt;That authenticity constraint is a feature, not a bug. It keeps us honest. It means every rules change is scrutinized. And it means the 3 million players who trust us have a very high bar for alternatives.&lt;/p&gt;

&lt;p&gt;If you're building in a cultural niche — lean into it. The niche is the moat.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;About: Jogos do Rei (&lt;a href="https://www.jogosdorei.com.br" rel="noopener noreferrer"&gt;jogosdorei.com.br&lt;/a&gt;) is Brazil's largest online card games platform, running since 2010.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;brazil&lt;/code&gt; &lt;code&gt;gaming&lt;/code&gt; &lt;code&gt;multiplayer&lt;/code&gt; &lt;code&gt;cardgames&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt; &lt;code&gt;startup&lt;/code&gt; &lt;code&gt;realtime&lt;/code&gt; &lt;code&gt;matchmaking&lt;/code&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gaming</category>
      <category>startup</category>
      <category>brazil</category>
    </item>
  </channel>
</rss>
