Doc > Integrations > Fxhash

Doc > Integrations > Fxhash

FxHash is a marketplace for generative art. You can buy and sell artworks that are unique and that are generated with code (or with Polygonjs!).

This tutorial explains how to prepare and export your scene in order to publish it on FxHash. You will then be able to create your interactive artwork, without coding and then upload it to the platform.

If you'd rather not read the whole tutorial below, you can:

But if you'd rather read, it's all here:

1. Add FxHash Code Snippet

As mentioned in FxHash Documentation, this site requires your artwork to have a code snippet that they provide in the index.html file.

So the first step is to add this snippet. And we want to have it loaded from inside the editor, so that we can use the function in our scene, and see how that affects it.

We'll then have to modify the src/polygonjs/EditorConfig.ts file that is created with you use Polygonjs local editor.

Note that you can see how it looks in the example project.

And let's start by adding the snippet like this:

options.api.html.head.addScript({
    id: 'fxhash-snippet',
    content: `
    //---- do not edit the following code (you can indent as you wish)
    let alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
    var fxhash = "oo" + Array(49).fill(0).map(_=>alphabet[(Math.random()*alphabet.length)|0]).join('')
    let b58dec = str=>[...str].reduce((p,c)=>p*alphabet.length+alphabet.indexOf(c)|0, 0)
    let fxhashTrunc = fxhash.slice(2)
    let regex = new RegExp(".{" + ((fxhashTrunc.length/4)|0) + "}", 'g')
    let hashes = fxhashTrunc.match(regex).map(h => b58dec(h))
    let sfc32 = (a, b, c, d) => {
        return () => {
        a |= 0; b |= 0; c |= 0; d |= 0
        var t = (a + b | 0) + d | 0
        d = d + 1 | 0
        a = b ^ b >>> 9
        b = c + (c << 3) | 0
        c = c << 21 | c >>> 11
        c = c + t | 0
        return (t >>> 0) / 4294967296
        }
    }
    var fxrand = sfc32(...hashes)
    // true if preview mode active, false otherwise
    // you can append preview=1 to the URL to simulate preview active
    var isFxpreview = new URLSearchParams(window.location.search).get('preview') === "1"
    // call this method to trigger the preview
    function fxpreview() {
        console.log("fxhash: TRIGGER PREVIEW")
    }
    //---- /do not edit the following code`,
});

After saving the file, you need to reload the editor. You don't need to restart it, but simply reload the browser page where you have it open http://localhost:8091.

If you open the console in the developer tools, you can check that the fxrand() is correctly loaded, and returns a different value everytime it is called.

fxrand function is loaded

Now, how do we have it affect our scene?

We can simply use it in any parameter, of any node. Which parameter you use it is up to you, as that depends on your scene and what you are trying to achieve, but the way to add it is by typing the following:

js("fxrand()")

Or if you type in a string, you need to add backticks (`) before and after.

`js("fxrand()")`

Once you have added that to a parameter, you can save your scene and reload the page. You should then see the scene update differently every time.

2. Features (optional)

FxHash also has a concept of features, which are ways to update your scene with specific values.

In order to add those features, you need to add another script, just like in the previous section.

The example below is for illustration, but should give you an idea. And again, if you're not sure, you can see how it is set up in the example project

options.api.html.head.addScript({
    id: 'fxhash-features',
    content: `
    function getFeatureString() {
        const value = fxrand();
        if (value < 0.5) return 0.1
        if (value < 0.9) return 0.5
        else return 1
    }
    window.$fxhashFeatures = {
        "Super": getFeatureString()
    }
    `
})

Let's now link those features to parameters in our scenes. We'll do that in a similar way to when we used fxrand()

js("$fxhashFeatures.Super")

Or if you type in a string, you need to add backticks (`) before and after.

`js("$fxhashFeatures.Super")`

3. Trigger the Preview

Fxhash is capable of creating a preview of the artwork. We need that preview to be captured only once our scene is loaded. So we to add another script for that:

options.api.html.head.addScript({
    id: 'fxhash-preview',
    content: `document.addEventListener('POLYViewerReady', fxpreview);`
})

When you get to upload in section 5, you'll be able to test that the previous works as expected.

4. Exporting

FxHash accepts a zip file, so let's setup the project so that this zip file is created whenever we save our scene.

Open the save Options, from the top menu with File->Save Options.

Set the options as follow:

  • Export should be checked
  • Compress Js should be unchecked
  • Create Zip should be checked
  • Publish For Integrations can be left as is.

You should see this:

Save Options

And now, if you save your scene, either with Ctrl+S or File->Save, you will see the following file structure:

Export Structure

You should see a zip file with your scene name inside the folder ./public/polygonjs/build. This is the one you should upload to fxhash.

5. Upload the zip to FxHash

We can now upload our zip file.

We'll skip the sandbox, as it does not seem to work with the way Polygonjs exports the javascript files. But don't worry, we'll have plenty of ways to check that our upload is working as we need it to.

So let's head to mint generative token, and you can drag and drop the zip file.

The preview will then appear.

You can then see the features (or variations) if you've set up any. Try them out and if you're happy with it, let's go to the next step.

Then you can specific how the preview capture is made. Use the following settings:

FxHash Preview Trigger Settings

And that's it! Now all you need to do is to define the price, description, and you're ready to add your artwork to the blockchain.

Any question? If you have any questions, or if you have stumbled on any bug in this tutorial, please do not hesitate to get in touch, I'll do my best to help you.

newsletter, twitter, forum or discord.

Is this doc helpful/not helpful? Is there any information you would like that is not available? Don't hesitate to get in touch with any question or feedback, either by email, on Discord or the forum.