# Nouns and Adding New Traits To Your Collection

By [denim](https://paragraph.com/@denim) · 2022-10-06

---

On August 8th, 2022 (Noun’s first birthday), 13 new traits were added to the Nouns protocol: 8 heads, 3 accessories, and 2 glasses ([https://nouns.wtf/vote/125](https://nouns.wtf/vote/125)). Let’s walk through the [code](https://github.com/nounsDAO/nouns-monorepo) that makes this possible.

![](https://storage.googleapis.com/papyrus_images/768e7f55a51d250d94132704165889ff347396f2edfdfb16bbe0263212f7f2aa.png)

The `NounsToken` contract uses three separate smart contracts to retrieve a given Noun’s art, which all lives on-chain:

*   `NounsDescriptor`: constructs an image for each Noun using artwork stored in the NounsArt contract
    
*   `NounsArt`: stores approved color palettes for the collection and the image data for each Nouns trait
    
*   `SVGRenderer`: takes stored pixel data and returns a corresponding SVG string that can be rendered on a browser
    

Step-by-step now:

1.  On minting a new Noun, the `NounsToken` contract generates a unique seed (a pseudo-random collection of integers) that determines the NFT’s attributes
    
2.  To render this Noun, `NounsToken` calls the `tokenURI` function in the `NounsDescriptor` contract which returns the corresponding token’s data
    
3.  The `NounsDescriptor` retrieves the pixel data associated with a given seed from the `NounsArt` contract and passes it to the `SVGRenderer` to get an SVG image for the Noun
    

Okay cool, but how do I add a new trait to the collection?
----------------------------------------------------------

Adding a trait to the collection means adding pixel data to the `NounsArt` contract. Let’s consider an example: how would you add a shark head PNG as a new Nouns trait?

![baby shark doo doo doo doo doo.png](https://storage.googleapis.com/papyrus_images/6470f011a485c304ee950552e82049528e31e7e9d5e027e49545e0de74e4bb4c.png)

baby shark doo doo doo doo doo.png

Shark head journey
------------------

![](https://storage.googleapis.com/papyrus_images/231c619b23bd986bfce7a9e398e66a110d46335ce0f66a8cc0066f37e781fca8.png)

### RLE Encoding

First, the shark head image gets encoded using a technique called [Run-Length-Encoding (RLE)](https://en.wikipedia.org/wiki/Run-length_encoding). This is done because on-chain data storage is expensive and encoding the image reduces the image’s size, and thus, the cost of storing it too. The trait image is encoded off-chain in a TypeScript class, `PNGCollectionEncoder`, which lives in the [nouns-sdk](https://github.com/nounsDAO/nouns-monorepo/blob/6328887f6cbe9bade0cdaf7ec2d6ed6eacbccfd4/packages/nouns-sdk/src/image/png-collection-encoder.ts#L9).

A quick look at the code reveals that the bulk of the encoding logic lives in an Image class function, `toRLE()`, which takes in a collection of colors stored in `NounsArt` as a parameter.

![](https://storage.googleapis.com/papyrus_images/bd7d36ecb953776798bff4d282f202bca0f9c04c3b9ff6bd331223584add2be0.png)

The `toRLE` function does three things:

1.  Calculates a boundary around the non-transparent part of a trait image
    
2.  Loops through the pixels within this boundary and stores their values in `indexes`, an array containing the trait’s color data
    
3.  Run-length encodes the data in `indexes` and returns it as a string of padded hex-encoded values
    

The GIF below illustrates how the program calculates this image boundary:

![](https://storage.googleapis.com/papyrus_images/14be4f3e74f298c03d74542cc0d03e6d5c0ccbe8920342ec914c5499862d8504.gif)

![RLE implementation per part C](https://storage.googleapis.com/papyrus_images/3d6c138634283c6911d3d07365463a8c6d1dd3116d16f8f91325a37702d40b6a.png)

RLE implementation per part C

The output of `toRLE` is then encoded further as a bytes array before being officially added to the Nouns protocol.

To push the trait on-chain, the Nouns DAO must vote to execute an Ethereum transaction that calls the appropriate `addTraits` function in the [NounsDescriptor](https://github.com/nounsDAO/nouns-monorepo/blob/6328887f6cbe9bade0cdaf7ec2d6ed6eacbccfd4/packages/nouns-contracts/contracts/NounsDescriptorV2.sol) contract (i.e. `addHeads`, `addGlasses`, etc) and passes the encoded image as a parameter.

This function then calls `addPage` which uses [SSTORE2](https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) (_a solidity library for reading and writing data to persistent storage on-chain)_ to store the encoded image in the `NounsArt` contract.

![The descriptor contract calls addHeads in NounsArt and passes in trait image data](https://storage.googleapis.com/papyrus_images/43a73187669fca089052cc23e57893391dffc32895b1da268e21c7091be212a4.png)

The descriptor contract calls addHeads in NounsArt and passes in trait image data

![The addHeads function passes an encoded head trait to the ](https://storage.googleapis.com/papyrus_images/40f328a55dfb62046cccc60a4e0f25296079bc30a4befc647d6f0cc439195ad7.png)

The addHeads function passes an encoded head trait to the

And… voila! A new shark head can now be assigned to a Noun as a trait.

Wrapping it up
--------------

If you want to learn more about Nouns and their plans to add new traits to the collection, check out `#noundry` in their [discord](http://discord.gg/nouns).

I wrote this walkthrough to highlight the affordances that come with storing data on-chain and to help others make sense of the Nouns smart contracts. If you’re working on a project with mechanics for showcasing collective group identities, I would love to chat :)

Huge shoutout to [Julian](https://twitter.com/0xjulian_) for edits and thoughts on the walkthrough.

---

*Originally published on [denim](https://paragraph.com/@denim/nouns-and-adding-new-traits-to-your-collection)*
