An Artblocks Retrospective


ORI is a long-form generative art project I released on Artblocks in November 2022. Making 450 unique mints involved carefully balancing variability and consistency to achieve my vision of unique and high-quality outputs. Along the way, I worked through a few challenges that I didn’t anticipate, and in the interest of helping other artists, I’ve published my experience.

Please keep in mind Artblocks processes may have changed from when I did things in 2022. This is an unofficial account of my experience with my project. All opinions are my own.

A generative artwork
ORI #96 (2022)


Prepare yourself: It may be very hard and very time-consuming to launch a project on Artblocks.

Artblocks is a closed platform requiring several quality gates to qualify for their most prestigious art tier: a curated release. It is a tremendous commitment to work through Artblocks, and it’s often unclear whether you’ll achieve your goals which can be discouraging.

Your journey starts with a project idea that you build into something worthy of applying to Artblocks. “Worthy” has a tricky definition here because the Artblocks curation board will deliberate on the metrics of your project and provide you with anonymous feedback afterward.

When I started working on ORI I set my sights on a curated release, but I underestimated the level of effort involved. I had to have faith that it was unique enough that I would get a shot, and that kept me going through months of intense programming sessions. At some point, it became all or nothing, and I had to surrender to the process and fully invest my time in the project. I would still do it again, but I’ve come to respect the sacrifices many artists make when developing complex, long-form generative projects.

Project Submission Tips

You should have a working prototype of a unique project before applying. Make sure that performance is acceptable, it works in all browsers, and bugs are squashed before submission.

Create a website or PDF of the project narrative, sample outputs, and other relevant details to describe the project. Your goal is to showcase a professional level of detail and thought behind the work.

I have come to appreciate the complete package of a project being much more extensive than its code bundle. A coherent and interesting story behind the work goes a long way in connecting to the board of curators, and fortunately, Artblocks may offer to work with you to refine this if you get accepted.

This vital point caused issues during my review: Tune your traits to be fairly equal. Do not create outputs with a 1-5% chance of appearing. You will want to display a healthy variety of outputs in 100-150 total test mints. When I submitted ORI, I had possible results that never appeared and limited the overall versatility of the project. Even in production, there’s one color variation that never appeared… Lessoned learned!

To sum up your checklist for applying:

  1. Hunker down; this is going to be hard and it’s going to take awhile
  2. Develop a narrative for the project
  3. Create collateral for your project for said narrative
  4. Have a prototype that functions well without bugs
  5. Tune your project to have diversity and not rarity
  6. Work to accept good or bad news. After submitting, it is out of your hands.

The importance of a quick feedback loop

When developing a generative art project, you will likely make thousands of code modifications and observe their results. It is critical to reduce this feedback loop to the bare minimum delay. If you manually refresh your browser, you’re wasting your most valuable resource, an attention span. Avoid any and all manual processes at all costs and instead focus on the truly difficult problems of creative coding: making something cool.

Ultimately, this is why I switched from Processing to P5JS. The latency in compiling my project was such a burden that I changed frameworks.

Fortunately, there’s tooling from the Web Development community to achieve a speedy development environment. To help others unfamiliar with these utilities, I’ve open-sourced my starter kit for Artblocks projects that uses Vite, which is the standard for iterative development.

View my Artblocks Gen Art starter on Github

Viewing a long-form collection

Eventually, I reached a point where viewing outputs one by one was tedious and myopic. I needed help to quickly identify deficiencies with the overall project that would only happen rarely, and manually refreshing my browser wasn’t cutting it. I needed a gallery view of outputs that I could quickly scan.

Custom Longform viewer

Sadly there’s no open-source solution to this problem, so I took a day to write my own application. My goal was to view hundreds of ORI outputs side-by-side, rank them, and inspect their traits. This way, I could quickly spot outliers, both good and bad. Then, I could modify the source code and observe the results at a macro scale.

While you can do this with your test net, I recommend against it for the same reasons mentioned above: It’s slow and tedious. With my system, I did 10-15 batch runs of 500-1000 outputs to curate the emergence.

Locking your seed

The beauty of a generative program is its ability to create an infinite number of artworks. Limitless possibilities also make debugging specific problems very difficult. For example, you may see a bug when X trait appears in Y order because Z is a particular value. Trying to reproduce these configurations manually is exceptionally tedious.

I created a basic and helpful way to handle these cases. Lock the seed value with a TX Hash that doesn’t change. Then your program will reproduce the same results reliably, and you can troubleshoot specific cases as they arise.

This opens up a workflow that I used extensively during my development:

Run random iterations -> Find a case where you would like to tweak -> Lock the seed -> Rerun the program and make tweaks -> Unlock the seed ↩

Know what browser incompatibilities there are

The last thing you want to happen is an escaped defect to be discovered by collectors. Feature support between browsers (especially Safari) could be better, even when working with canvas and WebGL. It’s essential to test your project cross-browser and across different devices and browsers to catch and correct problems. I can’t speak to having this problem myself, but apparently, GPU-based rendering can have different results on different hardware.

ORI #72 (2022)

Fighting PRNG drift

Your algorithm probably makes art based on a series of random() calls that Artblocks seed with a TX Hash. If your program calls a different number of `random() ’s at any time, you will get a divergent output. You may have even seen projects where the thumbnail doesn’t match the full-screen image, and this is likely the core reason.

In ORI I had this problem because of floating point imprecision issues. I calculated the polygon’s area and randomly drew dots inside it based on the size. Since the polygon size was related to the canvas size, I could get slightly different results if the canvas was very small or very large because I would have a different number of circles and, therefore, a different number of random() calls. The ensuing troubleshooting was nightmarish.

To debug such problems, add something like this as the final line in your program: console.log(Final PRNG: ${random());. Lock your seed value and run your program in different resolutions. If the number in the log ever changes, you have a problem. The number of times the PRNG is called is changing for some reason, and now you need to detect and fix it. You can use this logging strategy anytime in your program to hone in on where the irregularity is coming from.

In my case, I needed to devise a way to manage my geometry scaling differently to fix my bug.

box.x = 100; //bad
box.x = width/2; //good

I made everything in ORI relative to the size of the canvas. Everything. Including easy-to-miss things like stroke widths. It’s easier for me to use absolute numbers, so I developed some code to have the best of both worlds.

const setWidth = 900;
const realWidth = window.innerWidth;
const s = num => num * (setWidth / realWidth);

box.x = s(100);

I could think in absolutes using this helper function while also achieving dimensionless outputs.

There were other ways that dimensionless coding led to bugs with PRNG drift. Floating point issues arose when scaling geometry to extremes, so I needed another solution. The wise Tyler Hobbs recommended simply concatenating floats, which is probably the easiest solution.

I took a more complex path. I created all of the base geometry of ORI at an arbitrary size that was static; then, I computed the areas of my polygons. Since this was static, it was reliable. I then used those values in combination with a scale factor to drive my rendering engine. The resulting algorithm would render with the same PRNG outputs. Problem solved!

I also created quick links to view the same output at different resolutions to compare the rendering of thumbnails with large images. I switched back and forth between tabs to compare the results.

A Generative artwork
ORI #230 (2022)

Understanding your feature %

ORI has several features that get chosen at random. They are weighted instead of completely linear, because pure random() is often the most boring random().

Occasionally I would have scenarios like this:

let option1 = random() > .75 ? 'a' : 'b';
let option2 = option1 === 'a' && random() > .25 ? 'c': 'd';

How often will option2 be c? Not very often. But it’s unclear what the overall occurrence will be in a collection of 450 outputs.

Part of releasing on Artblocks is creating a feature script that powers the traits in the Artblocks UI. I would have liked to have made a script to run my features.js and logged the results to visualize the actual balance accurately.

In Conclusion

Working on a long-form project that’s permanently etched into the blockchain has been a saga filled with technical lessons. In the future, my approach will be much different starting so that I can avoid some of the tedium I’ve discovered. This is hard work, and focusing on the creative differentiators instead of the technical minutia is critical to maintaining sanity.