Technical Overview

A technical overview of the BitGen standard

The BitGen standard is represented above. Each hexagon is a unique inscription. The BitGen standard consists of the following inscription components:

  1. The Renderer JS

  2. The Collection JS

  3. The Collection JSON

  4. The Asset Layer IMAGES

  5. The Inscription HTML

  6. The Provenance JSON

Renderer JS

There are a few different ways to layer images:

  1. Use plain HTML and CSS to render images on top of one another

  2. Use a Canvas based approach "pasting" images onto each other on a Canvas

  3. Use an SVG approach layering each image as an SVG within a parent SVG

  4. Use an SVG approach with base64 images as SVGs within a parent SVG

After comparing each of these approaches, we've found #4 to be the most efficient and practical.

With #4 you get:

  1. Right-click save functionality as if it were a normal image

  2. The parent SVG can scale with the underlying SVGs (not the case with Canvas)

  3. You store images as bytes (33% smaller than base64) and convert them to base64 at run-time without any performance issues

  4. It supports PNG, WEBP, JPEG (for background), SVG, and GIF (still testing to get GIFs working).

Note: Ordinals are usually rendered in iframes to prevent cross site scripting attacks, and loading the iframe for each ordinal is the bottleneck for rendering as a wallet or marketplace.

INPUTS: The Renderer JS will be called by the Collection JS via /content/{renderer_inscription_id} and will accept inscription IDs as comma separated values for the "images" get param. It would look something like this:

/content/{renderer_inscription_id}?images={content_layer_1},{content_layer_2}

The image will be constructed with the first image at the very back, then the next image on top, etc. The earlier it is in the array, the further back it will be displayed in the image. Background will always be first.

OUTPUTS: The Renderer JS will return an SVG blob displaying the image as instructed by the get params.

Collection JS

The Collection JS is referenced by each individual inscription. The Collection JS does the following:

  1. Receives trait data from each individual inscription "2,6,4,1,0"

  2. It fetches the Collection JSON (Collection JSON inscription is hard coded)

  3. It uses the trait data to parse the Collection JSON to get the inscription IDs for the image

  4. It sources the Renderer JS as a script and passes in those inscription IDs

  5. It returns the SVG blob rendered by the Renderer JS

Collection JSON

The Collection JSON will contain all of the collection and image metadata. This includes (1) trait names, trait values, and trait inscription IDs for image metadata, and (2) collection name, collection description, and creator name for collection metadata.

The Collection JSON could have been included in the Collection JS directly, but we wanted to maintain interoperability with the Collection JSON. With the Collection JSON as a separate inscription, all you have to do for a marketplace to support your collection is give them the Collection JSON and the Provenance JSON. Two inscription IDs that contain all of the information needed to verify the provenance of your collection, list it on a marketplace, and enable metadata filters/sorting/rarity.

Asset Layers as IMAGES

Each asset layer will be inscribed separately on its own inscription. These asset inscriptions could be grouped together, but there is a 400KB limit on transaction size (mempools won't propagate transactions bigger than that), and you lose interoperability if you group them together. So to maximize interoperability and allow for larger layer file sizes, each asset should be inscribed separately. These asset inscription IDs will then be stored in the Collection JSON.

These asset layers can be JPEG (only for background), PNG, GIF, SVG, or Webp. File support is dependent on the Renderer HTML used to render the images.

Inscription HTML

The inscription will call the collection HTML using this syntax:

/content/{collection_html_inscription_id}?x={traits_data}

"x" is a get parameter for the traits data, which will look something like "1,6,4,2,12,9".

Note: the length of x when separated by "," should always equal the number of traits in the collection. Meaning if you don't want to display a trait layer, you need to leave it blank. This looks like this: "2,6,4,,2,3". Note the double comma between the "4" and the "2" indicating we shouldn't display anything for this trait.

This data could have been included in the Collection JSON, but we have deliberately chosen to include it in the individual inscription because you get the flexibility of changing the number of tokens you will inscribe after inscribing your collection JSON. If you had to include token information in the Collection JSON, as soon as you inscribed it everything would be locked in stone. Creators generally want flexibility with their collections, so the token trait data is included in each inscription.

Provenance JSON

The simplest way to inherit strong, provable, on-chain provenance for your collection is two-fold:

  1. Create a new Bitcoin wallet for your collection. Within this new wallet, create a single receiving address for your collection. Fund that single receiving address with Bitcoin to inscribe your collection. Once you have funded the address, you can do a sendMany to other receiving addresses to have UTXOs in order to inscribe. But only use this address to inscribe the collection. It shouldn't be used for anything else while you are inscribing your collection.

  2. Inscribe a Provenance JSON after you've inscribed everything in the collection using the same wallet as the collection. The Provenance JSON includes the bitcoin receiving address for the collection as well as the Collection JSON. This Provenance JSON should be the final element inscribed from the receiving address created in #1.

If you leverage both of these methods, then (1) all inscriptions can be provably traced back to the same receiving address (meaning nobody else can sneak an inscription into your collection even if they get access to the artwork), and (2) by inscribing the Provenance JSON you set the end of the inscription timeline for this receiving address.

Note: If you make a mistake inscribing, you can include the inscriptionId mistakes in the excludeInscriptions array. This will tell marketplaces that these inscriptions were mistakenly inscribed during the 'inscription period' and to not include them in the collection.

Once you've inscribed your Provenance JSON, you can safely transfer Bitcoin out of your collection wallet into another wallet.

Because (1) the Provenance JSON marks the end of the inscription window for the Bitcoin receiving address discussed above in #1, and (2) the Bitcoin address can be used for indexing inscriptions, this means a marketplace can integrate your entire collection by simply knowing a single inscription ID. All a marketplace needs is a Provenance JSON inscription ID and they can use the bitcoin address to find all valid inscriptions (all verifiable on chain), use each inscription to get the inscription traits, and then pull the Collection JSON file to give names to the traits.

If Marketplaces want extra assurance that you are the owner of the collection, they can require a BIP-322 signature that you own the Provenance JSON in the collection Bitcoin address.

Last updated