Examples
Two examples for a game called Orbit Dodger, one for each tier: a complete single page, and the scoring module of a bundled game. Both use one board, main.
Client tier, one page
A single page that loads the script tag and posts from the page. It draws its board on the game-over screen.
index.html
<!doctype html><html><head> <meta name="velven" content="@mara"> <script type="application/velven+json"> {"boards":[{"key":"main","trust":"client","metric":"points","sort":"desc","min":0,"max":100000,"cooldown":5}]} </script> <script src="https://velven.ai/sdk/v1.js"></script></head><body> <canvas id="game"></canvas> <ol id="board"></ol> <button id="sign-in" hidden>Sign in to be ranked</button> <script> const board = document.getElementById("board"); const signIn = document.getElementById("sign-in"); async function drawBoard() { const top = await Velven.scores.top({ limit: 10 }); if (!top.ok) return; board.replaceChildren(); // rows are other players' data: text only, never markup const line = (text) => { const li = document.createElement("li"); li.textContent = text; board.append(li); }; for (const r of top.rows) line(`#${r.rank} @${r.user.handle} ${r.value}`); if (Velven.user) { const mine = await Velven.scores.mine(); if (mine.ok && mine.row) line(`You: #${mine.row.rank} with ${mine.row.value}`); } } // The game fires this when a run ends; the score is the run's points. addEventListener("game:over", async (event) => { const result = await Velven.scores.submit(event.detail.points); if (!result.ok && result.error === "signed_out") signIn.hidden = false; // a guest: offer sign-in, never force it await drawBoard(); }); // Sign-in from a button, never on load. signIn.addEventListener("click", async () => { const auth = await Velven.signIn(); if (auth.ok) signIn.hidden = true; }); Velven.ready().then((environment) => { if (environment !== "site") drawBoard(); // "velven" inside Velven, "local" on your laptop }); </script></body></html>Server tier, bundled
A bundled game that posts through its own function, the one in Server scores.
game.js
import { Velven } from "@velven/sdk";const post = (path, body) => fetch(path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });export async function onRunOver(points) { const auth = await Velven.signIn(); // the player finished the run, so the card may show if (auth.ok) { // Your function verifies the token, then posts to Velven with the secret. await post("/api/score", { token: auth.token, value: points, request_id: crypto.randomUUID() }); } const top = await Velven.scores.top({ limit: 10 }); if (top.ok) drawBoard(top.rows, top.trust); // trust is "server" here; say so on the board}Velven.onAuth((user) => showName(user.handle)); // a later sign-in, through the card or another buttonNote: In a React app with a component of its own named Velven, import the SDK under another name: import { Velven as sdk } from "@velven/sdk".