# RMRK 2.0: Rich NFTs
_A proposal for Composable, Nested NFTs with conditional rendering logic and multiple resources at once._
NFTs should be dynamic and be able to evolve *with* and *on* the protocol they launched on. We propose an updated standard with a highly versatile base that's extendable by child NFTs inside the parent NFT, as well as some flags, switches, and on- and off-chain params and values.
The full spec is defined at the end of this propsal.
## Features
NFTs should be able to:
1. own other NFTs (nested NFTs).
2. define a visual base from which to inherit and on which to visually build, which can be local to an NFT (useful when single-instance), or external (useful for collections).
3. define slots on the base that define how NFTs equipped into those slots are treated with regards to, for example, transferability and visual interactions on the page.
4. define conditional logic that changes the visuals of these NFTs depending on certain triggers.
5. define multiple groups of 2-4, so that an NFT can have multiple resources at the same time.
We will now explain each point.
### Nested NFTs
By allowing the "owner" field of an NFT to be the ID of another NFT, we allow NFTs to own NFTs. Other NFTs can then own those NFTs, and so on.
Use cases:
- an inventory management system in a video game
- a user-made collection / bundle of NFTs for them to showcase or sell
- an NFT that changes appearance based on other owned NFTs
The owner of the root NFT can interact with a child any level deep. That is to say, an owner can put a Health potion that is in a their character's backpack up for sale directly, without having to interact with it through the characted NFT itself, or even the backpack.
### Visual Base and Base Slots
An NFT can be a composition of elements - a composition of Z-index stacked SVGs, for example. A visual base defines where the elements of an NFT's visual representation are, and where slots go, so that the NFT can be enriched.
Concretely:

This bird is holding a trumpet and a martini glass (placeholder items from the WIP stage of the [Kanaria](https://kanaria.rmrk.app) project). In order to render a trumpet, three elements work together: the wing, the "hand" of the wing, and the trumpet between these renders.
This is how this base defines this part:
```json=
{
"base":{
"type": "svg",
"id": "base-bird-rare-some-id",
"parts": {
"wing_1_back": {
"type": "fixed",
"z": 0,
"src": "ipfs://ipfs/hash"
},
"wing_1_front": {
"type": "fixed",
"z": 2,
"src": "ipfs://ipfs/hash2"
},
"wing_1_slot": {
"type": "slot",
"collections": ["MY_COLLECTION_OF_PROPS"],
"unequip": "burn",
"z": 1
}
}
// ...
}
}
```
In the example above, the base is defined as an SVG composition. For SVG compositions, it is assumed all parts are drawn in the same viewport of the parent, which means a simple overlay without coordinate information is enough to achieve adequate composition. It's worth noting that this does mean that a trumpet in the other wing is a **separate asset**. - TODO: multi resource help? If there's one resource for being equipped in one arm and another in another and we apply conditional rendering to decide which is shown, this is easy to fix.
The bird's wing 1 is composed of three parts: two fixed parts of the wing that aren't NFTs, just *parts*, and a slot into which a child NFT can go.
Slots ALWAYS host NFTs, and need to provide a whitelist of collections that can be equipeed into them. For "any", one should put `*` as the single element of the array.
The slot also specifies that an item can only be equipped into the wing if the owner is willing to accept that it will be burned on unequip - i.e. it is only usable on this character, similar to a "Soul bound" item in MMORPGs.
The "z" value defines the stack height of the SVG in the final render.
This base can be included in the NFT being minted, but can also be external:
```json=
{
"collection": // ...
"base": { /* ... */ }
}
```
vs.
```json=
{
"collection": // ...
"base": "base-bird-rare-some-id"
}
```
The latter approach allows for heavy caching of the base in the various UI elements, needing to assemble the base only once.
Once an NFT has been sent into another NFT, the owner NFT can EQUIP it into a slot. Only an equipped item will be shown on the render. TODO: define EQUIP.
### Conditional Logic
TODO consider conditional in children and their effect on base slots (trumpet left vs right case)
### Multiple Resources
TODO define priority for different and same type of resource
## Specification
### Base
The `Base` is a new RMRK entity which is used as a "class" or "library" for a composable NFT.
Every `resource` can have its own base. It is possible for an NFT to be composed of several non-interacting bases, through the use of different `resource` properties.
The base can be included in the NFT using it, or it can be referenced, in cases such as when it's being reused by different NFTs.
`Base` is a `json` object. Inside an NFT, it is keyed to the `base` propery in a single `resource`:
```json=
{
// ... NFT body
"base": { /* inline base */ }
}
```
or
```json=
{
// ... NFT body
"base": "hash_of_base"
}
```
The `Base` has the following properties:
- `type`
- type: string
- possible values: "svg"
- purpose: defining the type of the base, so the tools know how to compose the NFT when rendering it. Future values will include audio types, so you can compose music, video types so you can have interactive videos, and more.
- `parts`
- type: {key => PartDefinition}
- possible values:
- TBD
### Full Example
#### Base
```json=
{
"type": "svg",
"id": "some_id",
"parts": [
{
"bg": {
"type": "fixed",
"z": 0,
"src": "ipfs://ipfs/hash"
},
"gem_1": {
"type": "slot",
"collections": ["id-of-genesis-trait-crystals-LEGENDARY"],
"unequip": "unequip",
"z": 1
},
"gem_2": {
// ...
},
"gem_3": {
// ...
},
"gem_4": {
// ...
},
"gem_5": {
// ...
},
"wing_1_back": {
"type": "fixed",
"z": 1,
"src": "ipfs://ipfs/hash"
},
"wing_1_front": {
"type": "fixed",
"z": 3,
"src": "ipfs://ipfs/hash2"
},
"wing_1_slot": {
"type": "slot",
"collections": ["id-of-genesis-legendaries", "id-of-genesis-rares", "id-of-genesis-epics", ...],
"unequip": "burn",
"z": 2
}
}
]
}
```
#### NFT
Removed name, symbol.
SETFIELD(key, value)
SETFIELD("rain", "true")
```json=
{
"collection": "0aff6865bed3a66b-KANS",
"transferable": 1,
"sn": "0000000000000001",
"logic": [
{
">": ["emotes.🚀", 50],
"priority": [2,3,1] // change prio based on condition == true
},
{
">": ["emotes.❄", 100],
"resources.0.bg": "newhash" // overrides the background image in the base, if such a slot exists
},
{
"==": ["this.rain", "true"],
"resources.0.bg": "hash-of-rainy-background"
}
],
"priority": [1,0,2],
"resources": [
{
"base": "hash-of-base-svg.json"
},
{
"metadata": "hash-of-metadata-containing-guest-bird-art"
},
{
"metadata": "hash-of-metadata-guest-bird-art-with-jetpack"
}
],
"children": [
{"438637-0aff6865bed3a66b-KANS-oiyhi24yr28i7g4f": ""},
{"438637-0aff6865bed3a66b-KANS-oiyhi24yr28i7g4f": "wing_1_slot"},
{"438637-0aff6865bed3a66b-KANS-oiyhi24yr28i7g4f": ""},
{"438637-0aff6865bed3a66b-KANS-oiyhi24yr28i7g4f": "machine_gun_scope"},
]
}
```
Child 👇
```json=
{
"collection": "id-of-genesis-legendaries",
"transferable": 1,
"sn": "090183892798279",
"logic": "",
"priority": [1,0,2],
"resources": [
{
{
"base": "hash-of-base-svg.json"
},
{
"metadata": "hash-of-metadata-containing-guest-bird-art",
"slot": "some_id.wing_1_slot"
},
{
"metadata": "hash-of-metadata-guest-bird-art-with-jetpack"
}
}
]
}
```
#### Collection
Removed extras like in NFT. Focusing on this info in metadata.
```json=
{
"max": 9,
"issuer": "CpjsLDC1JFyrhm3ftC9Gs4QoyrkHKhZKtK7YqGTRFtTafgp",
"id": "0aff6865bed3a66b-KANS",
"metadata": "ipfs://ipfs/QmVgs8P4awhZpFXhkkgnCwBp4AdKRj3F9K58mCZ6fxvn3j"
}
```
TODO: polls example
TODO: custom fields in metadata, field overrides in NFT and in ops
TODO: conditional rendering based on those fields
TODO: JSONlogic examples of effects on renders (polls?)
TODO: Bird names as a custom field
###### tags: `rmrk`