Custom metadata renderers

The metadata for each collection type described above can be configured easily in the Highlight creation flows. It can also be updated after the contract is deployed. However, sometimes creators will want to customize their metadata in ways that arenโ€™t directly supported by the Highlight UI.

A walkthrough for launching a fully onchain Highlight project

Build your own onchain renderer

For these cases, Highlight supports the ability for creators to point to their own metadata โ€œrendererโ€โ€”another smart contract which will serve up the metadata however you like. To take advantage of this, you can invoke the following method on the ERC721GenerativeOnchain and ERC721GeneralSequence contracts (let us know at [email protected] if youโ€™d like to use this for other collection types), passing in the address where the renderer is served, and a boolean indicating whether to pass mint data to the renderer (in cases where, for example, you want to do something like store a random seed for a token at mint time).

struct CustomRendererConfig {
  address renderer;
  bool processMintDataOnRenderer;
}

setCustomRenderer(CustomRendererConfig calldata _customRendererConfig)

To implement your own custom renderer, simply ensure it adheres to the IHLRenderer.sol interface. If processMintDataOnRenderer is false, then the only integration that the contract has with your custom renderer is to hook into your renderer's tokenURI implementation, rather than it's own. If processMintDataOnRenderer is true, then the NFT contract will call the processing hooks on the IHLRenderer interface to process custom logic on your renderer. A common use for these hooks is to store a seed at mint time, where the seed is used when calling tokenURI on the renderer, to construct the metadata fully on-chain.

Deploy your Highlight collection

Once you launch your own custom renderer, go through the Highlight Generative flow and launch a Highlight collection. In the first step of that flow, you'll be asked to upload a local (offchain) version of your project. This powers cool UI features like cycling through example mint iterations on the mint page. For these cases, we recommend simply fetching preview outputs from your smart contract. We have a boilerplate, which can be found in sketch.js in the code below, which you can use to simply substitute in some of your own variables.

Demo zip from the video

Handling seeds

It's important that your onchain outputs match the outputs of the uploaded script. The demo above has the script query the contract to understand the output. In case you'd like to use a more complex, unpredictable seed (the demo uses the tokenId) that's generated onchain, or you'd like to avoid querying the chain on render every time, the Highlight Generative Engine provides an easy method for your renderer to pass a custom seed into the script at render time.

In a mint transaction, if the following event is emitted at any point from any contract in the transaction, the Highlight engine will pass the data field in as hl.tx.customMintData via hl-gen.js:

event CustomMintData(address indexed sender, address indexed contractAddress, bytes data);

Your script will need to use the seed as the renderer does to replicate outputs, rather than using the hl.random utilities. This means that if the renderer uses the seed to select entries in an array by seed % arrayLength, the script will also need to do this. Use the customMintData field as the seed if passed in, and default to using the transaction hash and tokenId combined as the seed if it doesn't exist, so that test outputs work properly on the mint page.

const onchainSeed = hl.tx.customMintData == "0x" 
 ? hl.tx.hash + hl.tx.tokenId 
 : hl.tx.customMintData;
 
// then use the onchainSeed to select outputs, just like the onchain renderer does
// for eg. if the onchain renderer mods the seed over the array length:
const colorCombinations = [...];
const selectedColorCombination = colorCombinations[
 BigInt(onchainSeed) % BigInt(colorCombinations.length)
];

CustomMintData

In general, the CustomMintData event is a way to pass any form of onchain data to your offchain script. This can be used to facilitate a wide array of use cases, like collector-curated seeds or fully onchain rendered projects.

Custom renderer interface

It's also important to note that if there is a TokenManager (management module) applied to an individual token, edition, or contract, then the metadata update logic enforced by the TokenManager will dictate whether the metadata update can happen.

Last updated