When it is your first time publishing on fx(hash) or any other platform, it can be pretty intimidating.

First, your perfectionism is kicking in, saying that your sketch needs more work.

Second, you need to make your project ready to be published.

For now, I will focus on helping you with some techniques I used while developing my project, Roses, to make it ready to be minted!

Abstract fxrand to random for easier use

For your project to be truly unique but also the same for each mint, you need to use a function provided by fxhash called fxrand() instead of the p5js provided random().

Fxhash provides a URL query parameter that functions as a seed. fxrand() uses this seed internally to display the same value based on the number of times it was called.

One trick that would make me think less about which random I'm using was abstracting fxrand() into a function.

The function takes two parameters, from and to, which are between where should the random function returns the numbers.

const random = (from, to) => {
	return map(fxrand(), 0, 1, from, to);
}

I had an issue where I used random throughout my project, changing it out manually was a big hassle, so this seemed like an elegant solution to the problem. It overrides the p5's random since it's in the local scope of the file!

Use random in the setup instead of the draw function

As mentioned above, fxhash uses a random query param to populate the seed of our random noise.

I struggled quite a lot to figure out how to make the output consistently the same. The easiest thing is that all your randomnesses should be set up during the project setup. In my example, I had three variables in my example: roughness, color, and size.

Then I refactored my code, so all the random elements in my code are generated in the setup() instead of in draw().

One way to make it accessible is to put your random variables into the global scope and then call them whenever you need them:

Const colors = ['#f1f1f1', ...]
const color;

function setup() {
	color = random(colors);
}

Make sure that your art is the same in all screen sizes.

One of the criteria for fxhash is that your code should look the same in all sizes. At first, hearing this, I thought to myself: "what the heck? How am I supposed to do that?"

I went to fxhash and searched through other projects to see what they did, and I came across a trick that helped me stay consistent through all screen sizes.

I used a bit of CSS to center my canvas and put it into position fixed. After that, I made the max width and max height 100%.

Here's the snippet:

body {
  margin: 0;
  padding: 0;
  width: 100%;
}
main {
  display: flex;
  justify-content: center;
}
canvas {
  max-width: 100%;
  max-height: 100%;
  margin: auto;
  overflow: auto;
  position: fixed;
  object-fit: contain;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

This makes the canvas HTML elements respond to different sizes, so it doesn't matter at what resolution you want to render the sketch (keep performance in mind, tho').

Minify the source code.

Since you want the person looking at your brand new NFT collection to enjoy it as quickly as possible, a good practice when you publish is to minimize the source code.

Minification is the process of making your source code smaller by replacing variable names with smaller ones, removing indentations and spaces, etc.

There are a couple of great tools that do this. If you are using a bundler such as a parcel or webpack, then they are probably already minifying the code in the bundle for you.

Otherwise, here are a couple of tools that I have found on the internet that does this:

Fire the fxpreview() when your sketch is finished

How does fx(hash) know when the sketch is finished?

There are two methods.

The first is by using a timer. When publishing, you can set after what time the sketch is finished, then grab a screenshot and display it as a preview.

Second, by using fxpreview().

fxpreview() is a function that fxhash is listening to, so it knows when your sketch is done rendering.

You have a lot more control with using this instead of timers, as timers can produce inconsistent results.

Let's say you have a range of 100 to 100000 objects that can go from left to right:

const objects = []
const objectsLength;
function setup() {
	createCanvas(900, 900);
	objectsLength = random(100, 100000)
	for(let i = 0; i < objectsLength; i++) {
		objects.push({x: 0, y: random(height), color: random(255)})
	}
}

function draw() {
	for(let i = 0; i < objectsLength; i++) {
		fill(objects[i].color)
		circle(objects[i].x, objects[i].y, 10);
		objects[i].x += 1;
	}
}

The speed of how fast this will go depends on the number of objects that need to be rendered, so timing the sketch can be pretty awkward since it's a guessing game.

Instead, we can add a check at the end of our draw function, which checks if the last object has come to the end of the sketch, and take the preview at that point:

...
function draw() {
	for(let i = 0; i < objectsLength; i++) {
		fill(objects[i].color)
		circle(objects[i].x, objects[i].y, 10);
		objects[i].x += 1;
	}
	if(objects[objectsLength] >= width) {
		// stops looping the draw function
		noLoop();
		fxpreview();
	}
}

Label the features

If we want fx(hash) to calculate the rarity of features correctly, we need to label them.

Let's see an example.

Let's say we have a variable of size, which can be between 1 to 3. If we use random(1,5), the values between can be infinite since random returns decimal values.

So a good practice is to set the ranges and label those values:

function getSizeLabel(num) {
  if (num >= 1) {
    return 'Extra Smal';
  }

  if (num >= 2 && num < 3) {
    return 'Medium';
  }

  if (num >= 3 && num < 4) {
    return 'Large';
  }

  if (num >= 4) {
    return 'Extra Large';
  }
}

function setup() {
	...
  const size = random(1,5);

  window.$fxhashFeatures = {
    Size: getSizeLabel(size),
  };
}

Add a saving feature.

It is an excellent practice to add a feature that allows people looking at your sketch to save it. Moreover, it enables the owners to repost it on social media in full resolution instead of screenshotting it.

Also, the image turns out precisely as you envisioned your sketch!

To add saving to your sketch, do this:

let cnvs
function setup() {
	cnvs = createCanvas(2400, 2400);
}

// p5js function that fires when
// a key is types
function keyTyped() {
  if (key === 's') {
	// save the image
    save(cnvs, 'image.png');
  }
}

We declare a global variable called, which saves the reference to the canvas. Then we declare a function called keyTyped() which p5js fires every time there is a keystroke.

It saves the current key that is typed into a global variable called key. We check if this key is the letter we wanted and save the image with the save() function.

Into  save() we pass the canvas variable (cnvs) and a name for our image as the second parameter.

Conclusion

In conclusion, publishing on fxhash or any other platform for the first time can be daunting, but with the proper techniques and strategies, you can make the process much easier. By using fxrand() instead of random(), making sure that your art is the same on all sizes by using a bit of CSS, minifying your source code, firing the fxpreview() when your sketch is finished, labeling the features, and adding a saving feature, you can ensure that your NFT collection is ready to be minted and appreciated by all. These tips will help you create a unique and polished project that stands out on the platform and makes a lasting impression on your audience.

How to make your generative art ready for fx(hash)?