| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>Faïence: a tile game against a neural net, in your browser</title> |
| <meta name="description" content="Faïence is a free, open-source implementation of the rules of Azul (Michael Kiesling). Play against a neural net trained by self-play. It runs entirely in your browser, no server, no install."> |
| |
| <meta property="og:type" content="website"> |
| <meta property="og:title" content="Faïence: a tile game against a neural net"> |
| <meta property="og:description" content="A free, open-source implementation of the rules of Azul. The net and its tree search run entirely in your browser: no server, no install, no account."> |
| <meta property="og:url" content="https://remifabre-faience.static.hf.space/"> |
| <meta property="og:image" content="https://remifabre-faience.static.hf.space/social.png"> |
| <meta property="og:image:width" content="1200"> |
| <meta property="og:image:height" content="630"> |
| <meta name="twitter:card" content="summary_large_image"> |
| <meta name="color-scheme" content="light"> |
| <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='4' fill='%2317509e'/%3E%3Crect x='6' y='6' width='9' height='9' rx='1.5' fill='%2331b8d1'/%3E%3Crect x='17' y='6' width='9' height='9' rx='1.5' fill='%23d99a12'/%3E%3Crect x='6' y='17' width='9' height='9' rx='1.5' fill='%23b23a26'/%3E%3Crect x='17' y='17' width='9' height='9' rx='1.5' fill='%23faf6ec'/%3E%3C/svg%3E"> |
| <link rel="stylesheet" href="css/style.css"> |
| </head> |
| <body> |
|
|
| <header class="topbar"> |
| <div class="brand"> |
| <span class="brand-name">Faïence</span> |
| <span class="brand-sub" id="matchup">a tile game for two</span> |
| </div> |
|
|
| <form class="setup" id="setup" autocomplete="off"> |
| |
| |
| <label class="field" id="bot-field" hidden> |
| <span class="field-label">Opponent</span> |
| <span class="bot-pick"> |
| <span class="bot-chip" id="bot-chip" aria-hidden="true"></span> |
| <select id="bot"></select> |
| </span> |
| </label> |
| <label class="field field-narrow"> |
| <span class="field-label">Seed</span> |
| <input type="text" id="seed" inputmode="numeric" placeholder="random"> |
| </label> |
| <label class="check"> |
| <input type="checkbox" id="first" checked> |
| <span>You go first</span> |
| </label> |
| <button type="submit" class="btn btn-primary" id="deal" disabled>Deal tiles</button> |
| </form> |
| </header> |
|
|
| |
| <div class="engine-bar" id="engine-bar"> |
| <span class="engine-dot" id="engine-dot" aria-hidden="true"></span> |
| <span class="engine-text" id="engine-text">Loading the net…</span> |
| <span class="engine-badge">runs entirely in your browser</span> |
| </div> |
|
|
| |
| |
| |
| <div class="news-bar" id="news" hidden> |
| <span class="news-badge">New</span> |
| <span class="news-text" id="news-text"></span> |
| <button type="button" class="news-close" id="news-close" aria-label="Dismiss">✕</button> |
| </div> |
|
|
| <main class="table"> |
|
|
| |
| <section id="status"></section> |
|
|
| |
| <section id="settings" aria-label="Settings"></section> |
|
|
| |
| |
| |
| <div class="playfield"> |
|
|
| <section class="panel middle-panel"> |
| <h2 class="panel-title">The middle of the table</h2> |
| |
| |
| <div class="hand" id="hand" hidden aria-hidden="true"> |
| <span class="hand-label">In hand</span> |
| <div class="hand-tiles" id="hand-tiles"></div> |
| </div> |
| <div id="middle"></div> |
| <div class="middle-actions"> |
| <span class="brand-sub" id="prompt">Loading the net. The tiles will be dealt in a moment.</span> |
| |
| <div id="nav" aria-label="Move navigation"></div> |
| <button type="button" class="btn" id="hint" disabled>Suggest a move</button> |
| <button type="button" class="btn hidden" id="cancel">Clear selection</button> |
| |
| |
| <div class="confirm-bar" id="confirm-bar" hidden aria-live="polite"> |
| <strong class="confirm-title">Validate this move</strong> |
| <span class="confirm-detail" id="confirm-detail"></span> |
| <button type="button" class="btn btn-primary" id="confirm">Play this move</button> |
| <button type="button" class="btn" id="confirm-cancel">Cancel</button> |
| </div> |
| </div> |
| </section> |
|
|
| <div class="boards"> |
| <section id="board-human" aria-label="Your board"></section> |
| <section id="board-ai" aria-label="The AI's board"></section> |
| </div> |
|
|
| </div> |
|
|
| <section id="scoring" hidden aria-live="polite"></section> |
|
|
| |
| |
| |
| |
| |
| <section class="panel record-bar" id="record" hidden> |
| <p class="record-note" id="record-note">Finished, and shared: the moves, |
| the tiles that were dealt, and which net you played are on their way to |
| the public training pile. Thank you. You can keep a copy too, or turn |
| sharing off in Settings.</p> |
| <div class="record-actions"> |
| <button type="button" class="btn" id="record-save">Save this game</button> |
| <button type="button" class="btn" id="record-copy">Copy as text</button> |
| <a class="record-link" id="record-dataset" |
| href="https://huggingface.co/datasets/RemiFabre/faience-games" |
| target="_blank" rel="noopener">See the public pile</a> |
| </div> |
| </section> |
|
|
| <div class="below"> |
| <section class="panel"> |
| <div class="board-head"> |
| <h2 class="panel-title" id="log-title">Move log</h2> |
| <label class="check coach off" id="coach-field" title="Score your moves with the AI's own search"> |
| <input type="checkbox" id="coach"> |
| <span>Coach mode</span> |
| </label> |
| </div> |
| <p class="coach-legend" id="coach-legend" hidden></p> |
| <ol class="log" id="log" aria-labelledby="log-title"></ol> |
| </section> |
|
|
| <div class="below-side"> |
| <section class="panel about" id="about" aria-labelledby="about-title"> |
| <h2 class="panel-title" id="about-title">What this is</h2> |
| <p>Faïence is a free, open-source implementation of the rules of |
| <em>Azul</em>, the tile-laying game by Michael Kiesling. It is a fan |
| project for research, with its own code and artwork, not affiliated |
| with or endorsed by the game's publishers.</p> |
| <p>All of it is open source (MIT): |
| <a href="https://github.com/RemiFabre/ludometer">code and training logs on GitHub</a>. |
| If you like this work, a star on the repo (or a hello in the issues) |
| is always appreciated.</p> |
| <p>Faïence began as a machine-learning experiment: Ludometer, a research |
| framework that measures how good a board game is from the shape of an |
| AI's learning curve. Somewhere along the way the experiment turned into |
| a pleasant opponent, so we are sharing it, playable and free. Nobody |
| earns a cent from this page: no ads, no account, nothing to buy.</p> |
| <p>The opponent is a neural network that learned the game from scratch |
| by playing against itself. Your browser downloads it once and runs it |
| locally.</p> |
| <p id="share-note">This is a research project, and the games are the |
| research material: when you play, you help the net train. So when a |
| game ends (or is abandoned), the page sends an anonymous record of it |
| to be used as training data: the moves, the tiles that were dealt, |
| which net you played, and the score. No name, no account, no |
| location. This is experimental, and there is a switch in Settings if |
| you would rather not. |
| <a href="https://huggingface.co/datasets/RemiFabre/faience-games" |
| target="_blank" rel="noopener">Every record is public</a>, so you can |
| read everything we collect.</p> |
| <p id="tally-note">Beyond that, the only thing that leaves your |
| browser is an anonymous, cookie-free tally of visits, games dealt, |
| and how finished games went. <a href="https://faience.goatcounter.com" |
| target="_blank" rel="noopener">It is public too</a>.</p> |
| <p class="about-meta" id="about-meta"></p> |
| </section> |
| </div> |
| </div> |
|
|
| |
| |
| |
| |
| <section class="panel bottom-bar" aria-label="Tile counts"> |
| <label class="field field-narrow" id="think-field"> |
| <span class="field-label">AI thinks for</span> |
| <select id="think"> |
| <option value="0">Instant (no search)</option> |
| <option value="3">3 seconds</option> |
| <option value="5" selected>5 seconds</option> |
| <option value="10">10 seconds</option> |
| </select> |
| </label> |
| <div class="counts" id="counts"></div> |
| </section> |
|
|
| </main> |
|
|
| |
| <nav class="corner" aria-label="About and statistics"> |
| <a class="corner-btn" id="corner-stats" href="https://faience.goatcounter.com" |
| target="_blank" rel="noopener" title="Public play statistics: everything this page records"> |
| <svg viewBox="0 0 20 20" aria-hidden="true"><rect x="3" y="10" width="3.4" height="7" rx="1"/><rect x="8.3" y="6" width="3.4" height="11" rx="1"/><rect x="13.6" y="3" width="3.4" height="14" rx="1"/></svg> |
| </a> |
| <button type="button" class="corner-btn" id="corner-about" title="What is this?">?</button> |
| </nav> |
|
|
| <div class="fly-layer" id="fly" aria-hidden="true"></div> |
| |
| |
| <div class="pop-layer" id="pops" aria-hidden="true"></div> |
|
|
| <script type="module" src="js/app.js"></script> |
| </body> |
| </html> |
|
|