chainrun.onenft.click

From one number to one runner

The only input is the clock of the Base chain: the timestamp of the current block. Nobody sets it and nobody can roll it back.

A day is that timestamp divided by 86,400, rounded down. That gives one calendar day in UTC, with the boundary at midnight UTC. The number itself counts days since 1 January 1970; day one of this project is day number 20701.

The layers are the 338 pieces Chain Runners drew on Ethereum in 2021 and released as CC0: 44 backgrounds, 15 races, faces, mouths, noses, eyes and seven kinds of accessory, 13 slots in all. Each is 32 by 32 pixels in eight colors with alpha, 416 bytes. The contract on Base holds all 338 byte for byte as they sit in the Ethereum renderer, along with its weight tables. The original picked each runner's DNA off chain; here the day number is the DNA.

The draw is thirteen numbers from 0 to 9,999, one per slot, out of splitmix64 seeded with the day. The race number decides which of three weight tables applies: human and alien, skull, or bot. Each slot's number walks its table; the item whose range holds it is worn, and a range past the last item means the slot stays empty. The original's rules apply unchanged: a mask hides the face, eye and mouth accessories; a face accessory hides the face and mouth accessory; a hat above the hair shows only on odd first draws.

The image composites the worn layers bottom to top with the original's blend: a semi-transparent pixel mixes once with the first opaque pixel below it. The result is one SVG, one rect per horizontal run of one color, a few kilobytes. The contract returns it as a data: URI, with no server in between. This page takes its colors from today's runner. Today: a Bot on Green Stripe. See every layer and how often it has come up.

The traits in the token are the worn layers, one attribute per slot, named as the Ethereum renderer names them.

Build it yourself

The same day number gives the same runner every time, ten years from now and with this page switched off. The generator is in the repository, in TypeScript and in Solidity, with a test that keeps the two byte for byte equal, and a second test that renders six Ethereum Chain Runners from their DNA and matches the original pixel for pixel. The draw is below; the layers, names and weight tables are in spec.json.

u64 mix(u64 x):
  x += 0x9e3779b97f4a7c15
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb
  return x ^ (x >> 31)

seed = mix(day)
for i in 0..12: dna[i] = mix(seed + i) mod 10000

race = table(WEIGHTS[0][1], dna[1])      # item 1 bot, items 12.. skull, else human or alien
for slot in 0..12:
  item = walk(WEIGHTS[race][slot], dna[slot])
  wear layers[slot][item] if it exists and the mask, face accessory and hat rules allow
pixel = blend(worn layers, top down)

Everything here is CC0, like the layers. If you build it, write to me. That is the one thing I am waiting for here.

Back to today. The parent project, one Truchet knot a day: onenft.click.