velven
Docs
Menu

Examples

2 examples for a game called Orbit Dodger, one for each trust tier, which sets who may post a score. The first is a complete single page that posts its own scores; the second is the scoring module of a bundled game that posts from its server. Both use one board, main.

View guide as Markdown

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;      // Rows are other players' data: text only, never markup.      board.replaceChildren();      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);      // A guest: offer sign-in, never force it.      if (!result.ok && result.error === "signed_out") signIn.hidden = false;      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) => {      // "velven" inside Velven, "local" on your laptop.      if (environment !== "site") drawBoard();    });  </script></body></html>

Server tier, bundled

A bundled game that posts through its own function, the one in Server scores. It asks for sign-in when a run ends rather than from a button, since the player chose to finish the run; the card's rules allow both.

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) {  // The player finished the run, so the card may show.  const auth = await Velven.signIn();  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 });  // trust is "server" here; say so on the board.  if (top.ok) drawBoard(top.rows, top.trust);}// A later sign-in, through the card or another button.Velven.onAuth((user) => showName(user.handle));

Note: 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".