$dmt-nat

Recursive demonstration

To create UNAT mint inscriptions with rendered content, the following represents an example that utilized recursive inscriptions. Feel free to use the open source script to your advantage to create your own UNAT.

Example

The mint inscription of a $dmt-nat looks like the following:

Mint Inscription
{
"p": "tap",
"op": "dmt-mint",
"dep": "4d967af36dcacd7e6199c39bda855d7b1b37268f4c8031fed5403a99ac57fe67i0",
"tick": "nat",
"blk": "319924"
}

If rendered properly, the inscription will appear like the following:

Rendering Mints as Content

Mint inscriptions use the "dep" attribute in the JSON to point back to the $dmt-nat deployment inscription that looks like the following:

Deployment Inscription
{
"p": "tap",
"op": "dmt-deploy",
"elem": "63b5bd2e28c043c4812981718e65d202ab8f68c0f6a1834d9ebea49d8fac7e62i0",
"tick": "nat",
"dt": "n",
"id": "61756c3e2dbcfbdb889f7176014e583e94800721a7379a616ec2c031563a5000i0"
}

The deployment inscription above has an "id" attribute that points back to an on-chain script where an algorithm is inscribed as JavaScript, and instantiated from multiple inscriptions with unique seeds from the mint inscription above. The unique seed being the block height inside the mint inscription.

The following script was used to render the images that make up the UNAT for $dmt-nat mints. Each mint inscription is a unique art piece rendered from Bitcoin's block data. Recursive images were used in this script and serves as a starting point for any creator to use this script to render their own content.

<canvas id="root" width="256" height="256"></canvas>
<input id="input" type="number" style="display:none" />
<script id="preview" mint="MINT_INSCRIPTION_ID">
const canvas = document.getElementById('root')
const ctx = canvas.getContext('2d')

canvas.parentElement.style.width = '100%'
canvas.parentElement.style.height = '100%'
canvas.parentElement.style.padding = '0px'
canvas.parentElement.style.margin = '0px'

const orgWidth = 462
const orgHeight = 462
let blockNumber = '0'

let scaleW = 0
let scaleH = 0
let offsetX = 0
let offsetY = 0

let background = new Image()
background.onload = redraw
background.src = '/content/45a7abf8aeab54c8b1ae87e05e502fd13b13984cc60101fd862c954b60cce678i0'

let center = new Image()
center.onload = redraw

let orb0 = new Image()
orb0.onload = redraw

let orb60 = new Image()
orb60.onload = redraw

let orb120 = new Image()
orb120.onload = redraw

let orb180 = new Image()
orb180.onload = redraw

let orb240 = new Image()
orb240.onload = redraw

let orb300 = new Image()
orb300.onload = redraw

window.addEventListener('resize', resize, true)
resize()

// Retrieve mint inscription id
let mintText = document.getElementById('preview').getAttribute('mint')

// Check no mint provided
if(mintText.includes('MINT_INSCRIPTION_ID')) {
  let input = document.getElementById('input')
  input.style.display = 'block'
  input.style.position = 'absolute'
  input.style.fontSize = '20px'
  input.style.margin = '20px'
  input.style.top = '0'
  input.value = blockNumber
  input.addEventListener('input',(event) => {
      blockNumber = input.value
      update()
  })
  update()
}
// Mint was provided
else {
  const request = new XMLHttpRequest()
  try {
    request.open('GET', '/content/' + mintText)
    request.responseType = 'text'
    request.addEventListener('load', () => initialize(request.response))
    request.addEventListener('error', () => console.error('XHR error'))
    request.send()
  } catch (error) {
    console.error(`XHR error ${request.status}`)
  }
}

function initialize(result) {
  if(result) {
    console.log('Result', result)
    data = JSON.parse(result)
    blockNumber = data.blk
  }
  update()
}
function update() {
  center.src = getCent(getChar(blockNumber, 0))
  orb0.src = getOrb(getChar(blockNumber, 1))
  orb180.src = getOrb(getChar(blockNumber, 2))
  orb60.src = getOrb(getChar(blockNumber, 3))
  orb240.src = getOrb(getChar(blockNumber, 4))
  orb120.src = getOrb(getChar(blockNumber, 5))
  orb300.src = getOrb(getChar(blockNumber, 6))
}
function resize(event) {
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  scaleW = canvas.width / orgWidth
  scaleH = canvas.height / orgHeight
  offsetX = 0
  offsetY = 0
  if(scaleH < scaleW) {
    scaleW = scaleH
    offsetX = (canvas.width - orgWidth * scaleW) / 2
  }
  else {
    scaleH = scaleW
    offsetY = (canvas.height - orgHeight * scaleH) / 2
  }
  redraw('resize')
}
function redraw(item) {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  drawImageScaled(background, orgWidth/2, orgHeight/2)
  drawLineScaled(getColor(getChar(blockNumber, 7)), 231, 231, 231, 98)
  drawLineScaled(getColor(getChar(blockNumber, 9)), 231, 231, 341, 158)
  drawLineScaled(getColor(getChar(blockNumber, 11)), 231, 231, 341, 291)
  drawLineScaled(getColor(getChar(blockNumber, 8)), 231, 231, 231, 364)
  drawLineScaled(getColor(getChar(blockNumber, 10)), 231, 231, 121, 291)
  drawLineScaled(getColor(getChar(blockNumber, 12)), 231, 231, 121, 158)
  drawArcScaled(getColor(getChar(blockNumber, 13)), 231, 230, 132, 0, 60)
  drawArcScaled(getColor(getChar(blockNumber, 15)), 231, 230, 132, 60, 120)
  drawArcScaled(getColor(getChar(blockNumber, 17)), 231, 230, 132, 120, 180)
  drawArcScaled(getColor(getChar(blockNumber, 14)), 231, 230, 132, 180, 240)
  drawArcScaled(getColor(getChar(blockNumber, 16)), 231, 230, 132, 240, 300)
  drawArcScaled(getColor(getChar(blockNumber, 18)), 231, 230, 132, 300, 0)
  drawImageScaled(center, 231, 231)
  drawImageScaled(orb0, 231, 100)
  drawImageScaled(orb60, 341, 158)
  drawImageScaled(orb120, 344, 294)
  drawImageScaled(orb180, 231, 362)
  drawImageScaled(orb240, 118, 294)
  drawImageScaled(orb300, 121, 158)
}
function drawArcScaled(color, x, y, radius, startDeg, endDeg) {
  ctx.strokeStyle = color
  ctx.lineWidth = 6 * scaleW
  ctx.beginPath()
  ctx.arc(offsetX + x * scaleW, offsetY + y * scaleH, radius * scaleH, (-90 + startDeg) * Math.PI/180, (-90 + endDeg) * Math.PI/180)
  ctx.stroke()
}
function drawLineScaled(color, x1, y1, x2, y2) {
  ctx.strokeStyle = color
  ctx.lineWidth = 6 * scaleW
  ctx.beginPath()
  ctx.moveTo(offsetX + x1 * scaleW, offsetY + y1 * scaleH)
  ctx.lineTo(offsetX + x2 * scaleW, offsetY + y2 * scaleH)
  ctx.stroke()
}
function drawImageScaled(img, x, y) {
  if(img == null) return
  ctx.drawImage(img, offsetX + (x - img.width/2) * scaleW, offsetY + (y - img.height/2) * scaleH, scaleW * img.width, scaleH * img.height)
}
function getChar(str, char) {
  return char >= str.length ? '0' : str.charAt(str.length - 1 - char)
}
function getCent(char) {
  switch(char) {
    case '0': // red
    default:
      return '/content/4ccae73d757bc81567c08b178dadc0f941ca5b590d8872d20b91b9aa0026c094i0'
    case '1': // orange
      return '/content/071839e2b743d6f0dde610318a94ea31688ad1ef7a466e1e49effd0bcbbc5ec2i0'
    case '2': // green
      return '/content/57389900ae0d2f5e78a3f0837f3e2ca807a6564f02c1e91c7547087551eb6d37i0'
    case '3': // blue
      return '/content/e7f83ec5fb95780f91a6ab9de90b5a00161521b2972abc32abe3726d559b17f8i0'
    case '4': // yellow
      return '/content/f76f76b594c5fa4f249b262e5bc68ee86a7a57afa90805843da0de64011dba39i0'
    case '5': // purple
      return '/content/255c0405421faf818b873b2a28dad78e06412763cd7b9c008223bde37df16d6ai0'
    case '6': // gray
      return '/content/dc8586612e28d1147aaa4bd059b18e479ee81c51bd33120f9234a2623fce6d2di0'
    case '7': // light blue
      return '/content/a4e15da4d0fe1590d0447f4bebf1ac6503e2d800473d8417b866c8db79e86fbci0'
    case '8': // white
      return '/content/b5dea9454f94220b826e9a40a9550b06fdaeda99a7dc125506511744de881237i0'
    case '9': // black
      return '/content/497b17636cf3410ed01853a203f32bd19c73deadd13fa583706e18bbc84d0805i0'
  }
}
function getOrb(char) {
  switch(char) {
    case '0': // white
    default:
      return '/content/a44586031e19333c2ddeb3857ac8074897b4b7a9b5eb357cac02d9f960cc6087i0'
    case '1': // red
      return '/content/b641bfec1b6bec4f1a2ec26c269499dbad6192efbefff022e9a13d1436f435f2i0'
    case '2': // green
      return '/content/7416640b32d0423396374a9ea8da123b227ef0b99fcaa3f9b95de8a01f6fba35i0'
    case '3': // blue
      return '/content/9204e4f746de0a0e33fbd2454592473dc7aa027f251ac4147e4f96af91cad394i0'
    case '4': // yellow
      return '/content/2af78ab55427c0dffa501df64d8b9a5465a88e604bc878d33a1aafd9aeaf94bdi0'
    case '5': // purple
      return '/content/71cce084b6c1e01899e1917e7dc550053018629a930a3220382efabecb06a203i0'
    case '6': // gray
      return '/content/333ca2ee2b5399816a9b6eb2947ec19ab8a8a30470440e39bb4ce193ca24c2dfi0'
    case '7': // light blue
      return '/content/040378d2779d7d7f2a3df6d7de31e0e42f473c6b8428f070d94392ffa4ef196ci0'
    case '8': // orange
      return '/content/f20842305e554aa10e5266cf4cc119083c2a4928114195f40740075e4b70142ei0'
    case '9': // black
      return '/content/8ba3ff03dbc33a8d45b294a79ca91e9c8c2c8fc03a363f98e5c517422f49e13ai0'
  }
}
function getColor(character) {
  switch (character) {
    case '0': return 'white'
    case '1': return 'red'
    case '2': return 'green'
    case '3': return 'blue'
    case '4': return 'yellow'
    case '5': return 'purple'
    case '6': return 'gray'
    case '7': return 'lightblue'
    case '8': return 'orange'
    case '9': return 'black'
  }
}
</script>

Last updated