Seeds and parameters
A token's seed and every one of its parameter values come from one pure function of two inputs: the collection's id and the token's number. Nothing else feeds it, and nothing about it is stored anywhere as ground truth.
The pipeline
The collection id and token number are formatted into one string, hashed with SHA-256, and the resulting hex digest is the token's seed:
deriveSeedInput(collectionId, tokenNumber) // => "pons:v2:<collectionId>:<tokenNumber>" sha256Hex(input) // => 64 hex chars, the token's seed
The seed then seeds a small, fast PRNG called mulberry32, taken from its first four bytes. Each declared parameter draws one number from that generator, in the order the collection declared its params, and scales it into that parameter's [min, max] range:
function deriveParams(seedHex, specs) {
const rand = prngFromSeed(seedHex);
const params = {};
for (const spec of specs) {
const raw = spec.min + rand() * (spec.max - spec.min);
params[spec.key] = Math.round(raw * 10000) / 10000;
}
return params;
}Why mulberry32
mulberry32 does all of its math in 32-bit integers, with no floats in its internal state. That makes it stable across JavaScript engines: the same seed produces the exact same sequence of numbers whether it runs in a browser tab or on the server, which matters because both places derive a token's parameters independently and need to agree.
The seed float passed to shaders
Shaders don't receive the full seed hash. They receive a single f32 in [0, 1), built from the seed's first six hex characters, which is exactly 24 bits: enough to fit losslessly in an f32 mantissa with no rounding loss.
seedToFloat(seedHex) {
return parseInt(seedHex.slice(0, 6), 16) / 0x1000000;
}Determinism, end to end
- The derivation is a pure function of
(collectionId, tokenNumber). Given those two values and the collection's param specs, anyone can recompute a token's exact seed and parameters without touching a database. - The stored token row is a cache of that computation, not the source of truth. If it were ever lost, re-deriving it from the collection id and token number reproduces the identical values.
- The token number itself comes from whichever process assigns it at mint time (the chain, or the off-chain allocator), never from the minter. Nobody can pick or re-roll the outcome ahead of time.