DEV Community

Dr Abstract
Dr Abstract

Posted on

Introducing Rarity

Image description

FXHash is an NFT MarketPlace that focuses on Generative Art. They also let artists specify features of the art and calculate a rarity based on the number of times certain values appear for the features.

Image description

Above, we have the TimeLord WatchBands by the Author, Dr Abstract. The features can be seen at the right along with the percentages for their values. The total rarity is in the description at the left. The rarity can factor in the resell price for the NFT. The features are sent to FXHash with their specified object literal:

// FXHash feautures format
window.$fxhashFeatures = {
    "Bands (Trio)": bands,
    "Fidelity (Trio)": capitalizeFirst(size),
    "Complexity (Trio)": capitalizeFirst(complexity), 
    "Watch (Trio)": capitalizeFirst(watchType),
    "Material (Hex)": capitalizeFirst(effects),
    "Lineage (Trio)":lineage
}
Enter fullscreen mode Exit fullscreen mode

Rather than using a random number for a feature value it is best to pick certain values so the rarity calculations work better. For instance, if complexity could be a random number in a range from 0-100 then everyone would likely get a high rarity but if the odds are distributed to certain values then we can control the rarity.

Image description

ZIM at https://zimjs.com is a JavaScript Canvas Framework for coding creativity. We have added a rarity() function that helps distribute rarity. The function has two main settings, a simple setting and a payload setting - which builds in a look-up table.

// a simple version of rarity()
// pass in an object literal with feature and frequency
// rarity returns an array of features matching their frequency
// so there are 80 Mysterious, 5 Lady and 15 Lord strings
// the odds then will e 80/100, 5/100 and 15/100
// the total does not need to add to 100 
// note, the array is auto shuffled and we get the first item
const lineage = rarity({Mysterious:80, Lady:5, Lord:15})[0];
Enter fullscreen mode Exit fullscreen mode

Above we have the simple example - this returns a shuffled array of strings that match the frequency values. We get the first element so lineage will be probably Mysterious, but maybe Lord and unlikely be Lady. We then passed that into the Linage property of the FXHash object. If we needed to later, we could use a conditional on lineage to add a certain signature in the art.

// a payload version of rarity()
// here, we pass an array in as the feature value
// the array has the frequency first and then a payload 
// the payload can be any object
// again, we are getting the first element
// of the returned randomized rarity array
const size = rarity({
    tight:[1,5],
    perfect:[10,7],
    loose:[10,10],
})[0];

// we now have a String object stored in size
// for instance, this might be perfect.
// note we use capitalizeFirst(size) 
// this has two effects - it capitalizes
// but also converts the String object to a primitive string
// FXHash requires a primitive string
// but for the payload to work, size is a new String object

// here we use the payload that is stored on the String object
circle.scale = size.payload;
Enter fullscreen mode Exit fullscreen mode

Above we show how to access the payload. We could have used another object literal as a lookup table for the feature. But we decided to build it right in to the rarity() function. The only drawback is that the feature becomes a String or Number object so that it can hold the payload. So the result must be cast as a String or Number to turn it to a primitive - which happens to be needed by FXHash for its object. We have contacted them to request they auto cast and we shall see...

Here is a sample where we wanted to call the feature something special but then want blend modes to use. So we add the blend mode name to the payload position:

const effects = rarity({
    "electric":[20,"overlay"],
    "pixel":[5,"color"],
    "soft":[5,"soft-light"],
    "tron":[1,"destination-in"],
    "aztec":[1,"saturation"],
})[0];
Enter fullscreen mode Exit fullscreen mode

PLUCK, SEEDRANDOM, REPEATS

We have also added pluck() to grab a random element from an array. Previously, we would use shuffle(array)[0].

We have added repeats() to return how many times repeats occur in an array. This is a handy thing to base rarity on. For instance, rather than doing a rarity for a color of four different things, instead, base rarity on how many times a color repeats across the four different things.

let colors = [
    green.darken(.2),
    blue.darken(.2),
    yellow.darken(.2),
    pink.darken(.2)
]
let color1 = pluck(colors);
let color2 = pluck(colors);
let color3 = pluck(colors);
let color4 = pluck(colors);

let colorRepeats = repeats([color1, color2, color3, color4]); 
// will be 0,1,2 or 3
Enter fullscreen mode Exit fullscreen mode

We have added seedRandom() to seed the random number. This is important in how FXHash works - where based on the NFT ID, the generative art should generate the same art each time for that ID. So we just pass the FXHash variable to seedRandom() and it works perfectly. Any rand() we use or any of the ZIM VEE values for dynamic parameters, etc. will make the same set of random numbers for a specific seed.

seedRandom(FXHash);

// r1 will always be same for same seed
const r1 = rand(100); 

// r2 will probably different from above
// but will always be the same for the same seed
const r2 = rand(100); 
Enter fullscreen mode Exit fullscreen mode

So you see, we are working to make creating interactive and generative NFTs as simple as possible with ZIM.

To find out more - see our previous DEV post on making interactive NFTs or visit https://zimjs.com/nft

Cheers - please join us at https://zimjs.com/slack and https://zimjs.com/discord for our ZIM community!

Dr Abstract

Image description

Discussion (0)