← Back to Documentation Index

🌱 NFT Seed System

Deterministic world and art generation from token IDs, hashes, or numbers. Same seed = same output, always.

Sponsor

📋 Overview

The NFT Seed System enables deterministic procedural generation from any input — token IDs, blockchain hashes, or plain numbers. Every seed produces identical output across runs and devices.

💡 Key Features
  • FNV-1a Hashing — Convert any string (hex hash, token ID) to a 32-bit seed
  • xoshiro128** PRNG — High-quality seeded random number generator
  • Trait Mapping — Deterministic trait generation from schema definitions
  • ERC-721/1155 Metadata — Export standard NFT metadata JSON
  • Rich RNG Methods — random, range, float, pick, shuffle, gaussian, color, palette, weightedPick
  • Global Seed — setSeed() configures all subsystems (including voxel worlds)

🔧 Core Functions

createSeedFromHash(hashString)

Convert any string (hex hash, token ID, arbitrary text) to a deterministic 32-bit unsigned integer seed using FNV-1a hashing. Handles 0x prefix automatically.

hashString string — Any string: hex hash, token ID, name, etc.
Returns: number — Unsigned 32-bit integer seed
Example:
const seed1 = createSeedFromHash('0xabc123def456');
const seed2 = createSeedFromHash('my-token-42');
const seed3 = createSeedFromHash('12345');
// Same input always produces the same seed
createSeedRNG(seed)

Create a seeded pseudo-random number generator using xoshiro128**. Returns an RNG object with many utility methods for generating random values deterministically.

seed number — 32-bit integer seed
Returns: object — RNG object (see methods below)
Example:
const rng = createSeedRNG(42);

rng.random();           // float in [0, 1)
rng.range(1, 100);      // integer in [1, 100]
rng.float(0.5, 2.0);    // float in [0.5, 2.0)
rng.pick(['a','b','c']);  // random element from array
rng.shuffle([1,2,3,4]);  // Fisher-Yates shuffle (new array)
rng.gaussian(0, 1);     // normal distribution
rng.color();            // random hex color 0x000000-0xffffff
rng.bool(0.7);          // true with 70% probability
rng.palette(5);         // array of 5 harmonious hex colors
rng.weightedPick(
  ['common','rare','epic'],
  [70, 25, 5]
);  // weighted random selection
seedToTraits(seed, traitSchema)

Map a seed to deterministic traits using a schema definition. Supports categorical (with optional weights), float ranges, int ranges, and boolean traits.

seed number — 32-bit integer seed
traitSchema object — Schema defining trait types and ranges
Returns: object — Object mapping trait names to generated values
Example:
const traits = seedToTraits(42, {
  biome: {
    values: ['forest', 'desert', 'tundra', 'ocean', 'volcanic'],
    weights: [30, 20, 15, 25, 10],
  },
  elevation: { type: 'float', min: 0, max: 1 },
  hasRiver: { type: 'bool', probability: 0.4 },
  treeCount: { type: 'int', min: 5, max: 50 },
  rarity: {
    values: ['common', 'uncommon', 'rare', 'legendary'],
    weights: [60, 25, 12, 3],
  },
});
// traits = { biome: 'forest', elevation: 0.73, hasRiver: true, ... }
exportSeedMetadata(seed, traits, opts?)

Export ERC-721/1155 compatible JSON metadata from a seed and traits object.

seed number|string — The seed value
traits object — Traits object (from seedToTraits or custom)
opts object — Optional: { name, description, image, collection, version }
Returns: string — JSON string (ERC-721/1155 metadata format)
Example:
const json = exportSeedMetadata(42, traits, {
  name: 'Crystal World #42',
  description: 'A unique procedural world',
  image: 'ipfs://Qm...',
  collection: 'Nova64 Worlds',
});
// Returns JSON with { name, description, image, attributes, properties }

🌍 Global Seed Management

setSeed(hashOrNumber)

Set the global seed for all Nova64 subsystems. Accepts a number or hash string (auto-converts via FNV-1a). Automatically configures the voxel engine seed if active.

hashOrNumber number|string — Seed number or hash string
Returns: number — The resolved 32-bit seed
Example:
// Set from number
setSeed(42);

// Set from hash
setSeed('0xabc123');

// Set from token ID
setSeed('token-1234');

// Use the global RNG
const rng = getSeedRNG();
const value = rng.random();
getSeed()

Get the current global seed value.

Returns: number|null — Current seed, or null if not set
getSeedRNG()

Get the global RNG instance created by setSeed().

Returns: object|null — RNG object, or null if setSeed() not called

🎨 RNG Object Methods

The RNG object returned by createSeedRNG() provides these methods:

MethodReturnsDescription
rng.random()float [0, 1)Uniform random float
rng.range(min, max)integer [min, max]Inclusive integer range
rng.float(min, max)float [min, max)Float in range
rng.pick(array)elementRandom array element
rng.shuffle(array)new arrayFisher-Yates shuffle
rng.gaussian(mean, std)floatNormal distribution (Box-Muller)
rng.color()0xRRGGBBRandom hex color
rng.bool(p)booleanTrue with probability p (default 0.5)
rng.palette(n)array of hexn harmonious colors (analogous/complementary/triadic)
rng.weightedPick(items, weights)elementWeighted random selection
rng.seednumberOriginal seed value (property)

📊 Trait Schema Types

The seedToTraits() schema supports these trait definitions:

TypeSchema PropertiesOutput
Categorical{ values: [...] }Random element from values
Weighted{ values: [...], weights: [...] }Weighted random pick
Float{ type: 'float', min, max }Float in [min, max)
Integer{ type: 'int', min, max }Integer in [min, max]
Boolean{ type: 'bool', probability }true/false

🚀 Complete Example

Seed-Deterministic World Generation:
let traits, rng;

export function init() {
  // Convert token hash to seed
  const seed = setSeed('0xdeadbeef1234');
  rng = getSeedRNG();

  // Generate traits from schema
  traits = seedToTraits(seed, {
    biome: { values: ['forest','desert','tundra','ocean'], weights: [35,25,20,20] },
    elevation: { type: 'float', min: 0.2, max: 0.9 },
    hasCaves: { type: 'bool', probability: 0.6 },
    treeCount: { type: 'int', min: 10, max: 100 },
  });

  // Configure voxel world with seed (auto-set by setSeed)
  configureVoxelWorld({ renderDistance: 6 });
  updateVoxelWorld(0, 0);

  // Place seed-deterministic trees
  for (let i = 0; i < traits.treeCount; i++) {
    const x = rng.range(-80, 80);
    const z = rng.range(-80, 80);
    const y = getVoxelHighestBlock(x, z);
    if (y > 0) placeVoxelTree(x, y, z);
  }
}

export function draw() {
  print(`Seed: ${getSeed()}`, 10, 10, 0xffffff);
  print(`Biome: ${traits.biome}`, 10, 20, 0x00ffff);
  print(`Trees: ${traits.treeCount}`, 10, 30, 0x88ff88);

  // Press M to export metadata
  if (keyp('KeyM')) {
    const json = exportSeedMetadata(getSeed(), traits);
    console.log(json);
  }
}