nano133

Build · nano133 Kit

Nano for Three.js games

Your game can pay the winner the moment a round ends, with no fee. Play the game, then copy the code.

Coin Run

Demo · no real payment

How it works

One payout, start to end

  1. The game ends.The game sends the run’s number and what the player did: here, the moment of each jump.
    What it does not send

    It does not send a count of coins.

  2. The server checks the round.It plays those jumps again with the same rule file and counts the coins.
    Who decides the win

    The server started the run itself. It decides the win.

    What is refused

    A list that is no run is refused, and so is a run that ends sooner than its own length.

  3. The server sends the prize.From the game’s wallet to the player’s address, exactly once, and only inside its limits.
    The limits

    A prize limit for each player and a total for each day.

  4. The player’s wallet shows it.It is confirmed, usually in under a second, and no fee is taken from it.
    How it is confirmed

    The computers of the Nano network vote on the payment.

The server part, said plainly

On this page: the server's check of a run is real, and so is the Nano. A run of all 10 coins can make one claim at this site's faucet, with the faucet's own rules and limits: a new wallet, adults only, a few claims a day. It is the same claim that the faucet page gives with no game: the same amount, one time for a wallet. A win adds no Nano to it. So it is the faucet's gift, not a prize of the game, and this site has no prize wallet. The game says before the run when the faucet gives nothing. The arcade does the other half: its 1¢ rounds take their payment with Nano Checkout's amount and payment check, and the server plays each round again from its inputs (or, for the reaction test, checks its times) before it counts.

The package

@nano133/three does the server part for you: it starts a round, checks it with a replay, and pays the prize once. It is on npm, under the MIT license.

npm install @nano133/three

Its Firestore store uses firebase-admin, an optional peer: install it in your server app if you use that store. The package holds no wallet and no key; your server signs the payment.

Code to copy

Four small files. The first one is the same file that the game on this page and this site's server run.

Plain three.js: the picture, and the jumps of the run.

// game.js: plain three.js. It draws the run and records the jumps; run.js is the rule.
import * as THREE from "three";
import { BLOCKS, COINS, RUN, start, step } from "./run.js";

const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector("#game"), antialias: true });
const scene = new THREE.Scene();
// A side view: 8 units of the course across.
const camera = new THREE.OrthographicCamera(-4, 4, 3.4, -1.1, 0.1, 20);
camera.position.z = 10;
scene.add(new THREE.AmbientLight(0xffffff, 0.8), new THREE.DirectionalLight(0xffffff, 1.4));

const box = (w, h, color) => new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.5), new THREE.MeshStandardMaterial({ color }));
const floor = box(RUN.end + 20, 0.1, 0x35a8ff);
floor.position.set(RUN.end / 2, -0.05, 0);
const runner = box(RUN.wide, RUN.tall, 0xe9e9ee);
const coins = COINS.map((c) => {
  const m = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.3, 0.08, 24), new THREE.MeshStandardMaterial({ color: 0x209ce9 }));
  m.rotation.x = Math.PI / 2;
  m.position.set(c.x, c.y, 0);
  return m;
});
const blocks = BLOCKS.map((b) => {
  const m = box(b.wide, b.tall, 0xff6bd6);
  m.position.set(b.x, b.tall / 2, 0);
  return m;
});
scene.add(floor, runner, ...coins, ...blocks);

// 1. Ask YOUR server for a run. The server keeps the run's start time.
const { runId } = await (await fetch("/api/run", { method: "POST" })).json();

let pressed = false;
addEventListener("pointerdown", () => (pressed = true));
addEventListener("keydown", (e) => e.code === "Space" && (pressed = true));

const s = start();
const jumps = []; // the step number of each jump: this is what the server replays
const stepMs = 1000 / RUN.hz;
let last = performance.now();
let owed = 0;

renderer.setAnimationLoop(async () => {
  // 2. The rule moves in whole steps of 1/60 second, whatever the screen's speed is.
  const now = performance.now();
  owed += Math.min(now - last, 100);
  last = now;
  while (owed >= stepMs && !s.done) {
    owed -= stepMs;
    const jump = pressed && s.y === 0; // a jump counts only on the ground
    pressed = false;
    if (jump) jumps.push(s.step);
    step(s, jump);
  }
  runner.position.set(s.x, s.y + RUN.tall / 2, 0);
  coins.forEach((m, i) => (m.visible = !s.coins[i]));
  camera.position.x = s.x + 2;
  renderer.render(scene, camera);

  // 3. The run is over: send the jumps. The server counts the coins, and pays.
  if (s.done) {
    renderer.setAnimationLoop(null);
    const send = async () => (await fetch("/api/run/" + runId, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ jumps }) })).json();
    let answer = await send();
    // The server's clock for the run started a moment after the game's: when it says "too soon", wait and send again.
    while (answer.waitMs) {
      await new Promise((r) => setTimeout(r, answer.waitMs));
      answer = await send();
    }
    showResult(answer); // { won, coins, paid }
  }
});

Set it up with AI

Paste this into Claude, ChatGPT, Gemini or your coding agent, in your game's repository:

Add "pay the winner" to this Three.js game with Nano (XNO): when a player
wins a round, my server sends a small prize to the player's Nano address.
Follow this spec step by step: https://nano133.com/build/three/SPEC.md
Rules: the game's rule must be one pure file that the browser and the server
both run; the server starts each round (and makes its seed, if the game has chance),
replays the inputs and decides the win;
the wallet key stays on the server in a secret manager and is never printed,
logged or committed; add a prize limit for each player and for each day; make
each prize send exactly once. Ask me for the prize amount, the limits, the
node to use and how players sign in. Test with no real money first.

The agent follows the step-by-step spec, with the package or with the code to copy.

What comes next

Smart Model coming next

A coin slot as a 3D model that you put into a scene: a press asks for 1¢, and the game gets a "paid" event when the payment is confirmed.

Pay an object an idea we explore

Any mesh as a thing to pay: a door that opens, a look that changes, a sign that takes a tip.

More from the kit

MIT license · Source · npm · Three.js is a project of its own authors. This page is not from them.