text:
require 'cocos'

## get inscription  links
## e.g.
##    inscription/e8830c5fbdfc2f529350fd04a2ac20bb097dce98f159223837513ae3c8d05714i0
##  and export as tabular dataset (in .csv)

LINK_RX = %r{
              inscription/
                 (?<link>[a-fi0-9]+)
            }ix

def prepare_inscribes( slug, page_id, page_count )

  pages = (1..page_count).to_a
  pp pages

  txt = ""

  pages.each do |page|
    txt <<  read_text( "./sandbox/tmp/#{page_id}#{page}.html" )
    txt << "\n\n\n"
  end

  links = []

  rx = LINK_RX
  txt.scan( rx ) do |_|
    m = Regexp.last_match

    links <<  m[:link].strip
  end

  ## pp links
  puts "   #{links.size} link(s)"

  ## turn into symbol (to make uniq work ??)
  links = links.uniq
  ## pp links
  puts "   #{links.size} link(s) - unique"

  ## exclude
  ## links = links.reject { |link| EXCLUDES.include?( link ) }
  ## puts "   #{links.size} link(s)"

  recs = []
  links.each_with_index do |id, i|
     recs << [id]
  end

  headers = ['id']
  buf = String.new('')
  buf << headers.join( ', ' )
  buf << "\n"
  recs.each do |values|
    buf << values.join( ', ' )
    buf << "\n"
  end

  outpath = "./sandbox/tmp/ordinals.#{slug}.csv"

  puts "  saving >#{outpath}<..."
  write_text( outpath, buf )
end

pages = {
#  'diypunks'    => [ 'page', 31 ],
#  'diypunks-v2' => [ 'punk-ii/', 33 ],
#  'diyordibots' => [ 'bot', 44 ],
#   'diycoolcats' => [ 'cat', 27 ],
#    'btcwords' => [ 'word/', 32 ],
#  'diyordibots-v2' => [ 'iibot/', 40 ],
#   'diybirdies'  => [ 'bird/', 19 ],
#    'diyapes' => [ 'ape/', 4 ],
#    'diyaliens' => [ 'alien/', 4 ],
#   'diymartians'  => [ 'martian/', 4 ],
#    'orangepixels'  => [ 'pixel/', 4 ],
#    'diyphunks'  => [ 'phunk/', 1 ],
#    'diymaxibiz'  => [ 'maxibiz/', 4 ],
    'diyorditroops'  => [ 'troop/', 1 ],
}

pages.each_with_index do |(slug, h),i|
    puts "==>  [#{i+1}] #{slug} - #{h[1]} page(s)  ..."

    prepare_inscribes( slug, *h )   ## if i == 0
end

puts "bye"


text:
####
#  to run use
#    $ ruby ./sandbox/export.rb

## generate tabular spritesheet.csv
##    input -   spritesheet.png  + meta.csv (for name+category by id)

require 'pixelart'

meta = read_csv( './no1/meta.csv' )
puts "   #{meta.size} record(s)"

spritesheet = ImageComposite.read( './no1/spritesheet.png', width: 24, height: 24  )
puts "   #{spritesheet.count} tile(s) in #{spritesheet.tile_width}x#{spritesheet.tile_height}"

meta = meta.sort {|l,r| l['id'].to_i <=> r['id'].to_i }
pp meta

recs = []

meta.each_with_index do |rec,i|
  puts "==> #{i} - #{rec.inspect}"
  tile = spritesheet[i]
  blob = tile.image.to_blob
  puts "   #{tile.width}x#{tile.height} - #{blob.size} byte(s)"
  base64 = Base64.strict_encode64( blob )

  recs << [rec['name'], rec['category'], base64]
end

pp recs

headers = ['name', 'category', 'base64']
File.open( "./tmp/spritesheet.csv", "w:utf-8" ) do |f|
   f.write( headers.join( ','))
   f.write( "\n")
   recs.each do |values|
     f.write( values.join( ',' ))
     f.write( "\n" )
   end
end

## export to json
data = []
recs.each do |values|
   data << { 'name'     => values[0],
             'category' => values[1],
             'base64'   => values[2] }
end
pp data

write_json( "./tmp/spritesheet.json", data )

puts "bye"

repo_language: Ruby

mime_type: text/plain


text:
require 'ordinals'
require 'pixelart'

##############################
#   d.i.y. apes (attribute) inscribes

inscribes =
{
 'base' => 'b36750a6b444e3815f0cbb50a36e0f1231b74ba930855b1e9067f907942f34fci0',

 ## note - double check and make sure
 ##            NOT to mix-up female and male attributes!!!

## female?
##  ['f/3d_glasses', '0182710716a6706aa1aadcdf06d6f33a4edac1c2f86d2c9f5e0f2d1ca0ec3ee9i0'],
##  ['f/bandana', '44d6266aea36dd0dddaa57498a5f3658ad16cf888089905e72d3683b0366e086i0'],
##  ['f/regular_shades', 'b1d98f466e0b2aec940f2981b9c67a5d862871b5fad677a4e674aac36090b038i0'],
## ['f/cap', 'c60989760670968c917f8c19a49a09d9f163345bd1a1c61e9700415f67a0e96ci0'],

## male??
  'm/pipe' =>         '92e7f48454546718f98103d7464d954033adbee21855f06584be06faa3e291ddi0',
  'm/cigarette' =>   'a01012b213ed425c5d4038bc36016f19f4f342ca052ff9bf6971672164e1a402i0',

  'm/nerd_glasses' => 'd61fc2a89ecc6ae65cf91cdfac9edc37fd60c38621dac211f3a70891ef79b69ai0',
  'm/vr'   =>         '680e2ee8cad86aa174b4f3373d733370c9a6fc4230b9708d520a0f6bcb8e72a6i0',
  'm/3d_glasses' =>  '56d3f4f661b2b4a9fc17755171d7cf4da74e570614b6b45de0cc87a809c3eb3ci0',
  'm/eye_mask'  =>     'fe4321178bd841e52fdeb72ce4456c5b7596c0d611b19da15ba75ec63b5314cai0',
  'm/regular_shades' => 'eddc1242f0fd290e130332e046897ad41dce1e7e112df48ecf2168e43172d383i0',
  'm/small_shades' => 'a2110fb4afaa29bc70bcfac445f750ecb5e81777e8d080be2d2b07eb030ba0ffi0',
  'm/horned_rim_glasses' => 'c1277df4b986067b2a3f006d717b7f6d042896840c8b592e5a8b9ff22444b08fi0',
  'm/bandana' => 'a6b4b81f69e8c217db24f0a71954195d67ced49a819b67a4daf9f3ca7fa1b971i0',
  'm/earring' => '06136a5b4fb585069ef6265a0fde3baf67ee914b9f784d2c951f3a8187800d54i0',
  'm/spots'  =>   '1355524a2aab576e069bac91227b0e52d227d65d84c5535377d3a0ea4e44d470i0',
  'm/knitted_cap' => '7c2fd41b52624ddb1ba11fe1c6d95475f2e42c4b53d6aaf6a16a09064acebe38i0',
  'm/headband'  => '83827ec13cb55a35fe3adca5acf67caf943c3bd6810f8fa893b067e8015c8f19i0',
  'm/tophat'  => '5b1e638c050318bec23f17b8b7758ccf13945e422516da6c722c67ae5ed4e26di0',
  'm/eye_patch' => '722dfdc90a67ff7eb892d13393a8a5b360b8a109f3d809600919684a600ff60ei0',
  'm/mohawk'  =>   '5ce9f89ad571e5380baa5b5ee387f08ea313421e7e54662b3899d411c39321ddi0',

  'm/hoodie'  => 'aab67a4269ca0bda649fe341bd88c862aba2e9bf6e0826b9dfa5c4ba8fe62c2di0',
  'm/cowboy_hat' => '5dcf96b13e5762d5a288d8bee36deb933fe192a55475199fe9a39ae29dd16853i0',
  'm/beanie'  =>  '0f473c9dcd14e3f43a6599b038d810eac16bc6394edcfcf6b32f8df992ab6791i0',
  'm/cap_forward' => '0bd902941392ea138adb7db30cecdf5bc09a92c80e3e1bc3ecdf3c2d0abf6631i0',

  'm/cap'  => '5760ce05009e94a750a7245cac994fa9ffd388eadc757929ac17737811455429i0',

  'm/dorag' => 'd32c50c23693a028e2381d6f756746a9ff684f2028edf694ab7b1b6cde78e2cdi0',
  'm/medical_mask' => '87d89d290ebde5d5b7aa75b4c8d0359515e25ea1542bc0646dc3f5b0b2fc55fdi0',
  'm/goldchain' => '8043604c7c96a5a43a97e251b246102ca40c0203431ff21bd26f23330dfa554ci0',
}

pp inscribes

inscribes.each_with_index do |(name,id), i|

  puts "==> #{i} - #{name} @ #{id}..."

   ## note: assume png - double check?

   path = "./tmp/apes/#{name}.png"
   force = false  ## download & overwrite if exists

   if force == false && File.exist?( path )
      puts "  #{name} in cache"
   else
     content = Ordinals.content( id )
     pp content
     #=> #<Ordinals::Api::Content:0x000001a1352df938
     #      @data="RIFF\xF8\v\x00\x00WEBPVP8 \xEC\v\x00\x00...",
     #      @length=3072,
     #      @type="image/png"

     puts "data:"
     puts content.data

     write_blob( path, content.data )

     sleep( 0.5 )
   end
end

###
## assemble into spritesheet

attributes =
[
  'base',
  'm/mohawk',
  'm/spots',

  'm/bandana',
  'm/headband',
  'm/tophat',
  'm/cowboy_hat',
  'm/cap',
  'm/cap_forward',
  'm/knitted_cap',
  'm/beanie',
  'm/dorag',

  'm/nerd_glasses',
  'm/vr',
  'm/3d_glasses',
  'm/eye_mask',
  'm/regular_shades',
  'm/small_shades',
  'm/horned_rim_glasses',
  'm/eye_patch',

  'm/earring',
  'm/goldchain',

  'm/pipe',
  'm/cigarette',
  'm/medical_mask',

  'm/hoodie',
]

puts "  #{attributes.size} attribute(s)"

composite = ImageComposite.new( 10, 3, width: 24,
                                       height: 24 )

attributes.each do |name|
  path = "./tmp/apes/#{name}.png"
  img = Image.read( path )
  composite << img
end

composite.save( "./tmp/apes/spritesheet.png" )
# composite.zoom(4).save( "./tmp/apes/spritesheet@4x.png" )
# composite.zoom(8).save( "./tmp/apes/spritesheet@8x.png" )

###
## assemble generative array (jsom)

data = []
attributes.each do |name|
  id = inscribes[name]

  if id.nil?
    puts "!! ERROR - inscribe for >#{name}< not found; sorry"
    exit 1
  end

  data << id
end

puts "  #{data.size} id(s) in generative:"
pp data

write_json( "./tmp/apes/generative.json", data )

puts "bye"


text:
require 'ordgen'

slug = 'diymartians'
width  = 24
height = 24
max    = 100

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path =   "./docs/#{slug}/spritesheet.png"

diymartians  = Ordgen.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = diymartians._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = diymartians.generate( *g )

  composite << img
end

composite.save( "./tmp2/diymartians.png" )
composite.zoom(4).save( "./tmp2/diymartians@4x.png" )

###############
#  generate NO background version (40-49)

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = diymartians._parse( rec['g'] )
  ## remove backgrounds (40-49)
  g = g.select {|num| num < 40 }
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = diymartians.generate( *g )

  composite << img
end

composite.save( "./tmp2/diymartians-remove_background.png" )
composite.zoom(4).save( "./tmp2/diymartians-remove_background@4x.png" )

puts "bye"


text:
require 'ordgen'

module Pixelart

class Image

  ## neon glow special effect
  def neon( color, invert: false )

    ## find color - assume 1-bit (one color only)
    colors = pixels.uniq.sort    ## let 0 (transparent go first)

    if colors.size != 2 && colors[0] != 0
      puts "!! ERROR - 1-bit image expected; got #{colors.inspect}"
      exit 1
    end

   foreground = colors[1]

    img = if invert
              change_colors( {
                foreground => 0,
                0     => foreground
              })
          else
             self
          end

     ## transparent & white
    inverse1 = img.change_colors( {
              foreground => 'ffffff',  ## 1-bit color to white
            })

    ## transparent & color
    inverse2 = img.change_colors( {
                foreground => color,  ##  1-bit color to color
           })

####
# inspired by
#   https://css-tricks.com/how-to-create-neon-text-with-css/
#
# .neonText {
#    color: #fff;
#    text-shadow:
#      // white glow
#       0 0 7px #fff,
#       0 0 10px #fff,
#       0 0 21px #fff,
#      // green glow
#       0 0 42px #0fa,
#       0 0 82px #0fa,
#       0 0 92px #0fa,
#       0 0 102px #0fa,
#       0 0 151px #0fa;

    base = Image.new( width, height, Color::BLACK )
    base.compose!( inverse2.blur( 12 ) )  # -blur 21x21
    base.compose!( inverse2.blur( 6 ) )  # -blur 10x10
    base.compose!( inverse2.blur( 4 ) )   # -blur 7x7

    base.compose!( inverse1.blur( 2 ) )   # -blur 2x2
    base.compose!( inverse1 )
    base
  end
end # class Image
end # module Pixelart

slug = 'orangepixels'
width  = 24
height = 24
max    = 100

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
## recs = recs[0, max]
## puts "   #{recs.size} record(s)"

spritesheet_path =   "./#{slug}/spritesheet.png"

orangepixels  = Ordgen.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

composite_neon  = ImageComposite.new( 10, 10, width: width,
                                              height: height )

invert_ids = [5,10,11,34]

recs.each_with_index do |rec,i|
  g = orangepixels._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = orangepixels.generate( *g )

  composite << img

  ## color = 'ff9900'  ## bitcoin orange
  ## color = '00ff00'  ## green
  color = '0000ff'  ## blue
  ## composite_neon << img.neon( color, invert: invert_ids.include?( i ) )
end

composite.save( "./tmp2/orangepixels.png" )
composite.zoom(4).save( "./tmp2/orangepixels@4x.png" )

## composite_neon.save( "./tmp2/orangepixels_neon.png" )
## composite_neon.zoom(4).save( "./tmp2/orangepixels_neon@4x.png" )

puts "bye"


text:
require 'ordgen'

#######
#   collection (config) setup here ...

max = 721

###
#  start processing...
recs = read_csv( "./diybirdies/mint.csv" )
puts "   #{recs.size} record(s)"

# cut-down to max. limit
# recs = recs[0, max]
# puts "   #{recs.size} record(s)"

diybirdies = Ordgen.read( "./diybirdies/spritesheet.png",
                             width:  24,
                             height: 24 )

## 30 cols x 25 rows = 750
composite = ImageComposite.new( 30, 25, width: diybirdies.width,
                                        height: diybirdies.height )

recs.each_with_index do |rec,i|
  g = diybirdies._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"

  composite << diybirdies.generate( *g )
end

outname =  "./tmp2/diybirdies_max#{max}"

composite.save( "#{outname}.png" )
composite.zoom(4).save( "#{outname}@4x.png" )

puts "bye"


text:
require 'pixelart'

## step 1 - read (local) spritesheet.png ("art layers")

btcwords   = Orc721::Generator.read( './btcwords/spritesheet.png',
                                          width: 102,
                                          height: 32 )

recs = read_csv( "./btcwords/mint.csv" )
puts "   #{recs.size} record(s)"

## cut down to first fifty, next fifty
[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800].each_with_index do |offset,i|
  puts "==> page #{i+1} starting at offset #{offset}"
  batch = recs[offset, 50]
  puts "   #{batch.size} record(s)"

  composite = ImageComposite.new( 5, 10,  width:  btcwords.width,
                                          height: btcwords.height )

  batch.each_with_index do |rec,i|
    num = rec['num']
    g   = btcwords._parse( rec['g'] )
    puts "==> no. #{i+offset} @ #{num}  g: #{rec['g']} - #{g.inspect}"
    img = btcwords.generate( *g )

    # img.save( "./tmp/btcwords#{i+offset}.png" )
    # img.zoom(4).save( "./tmp/btcwords#{i+offset}@4x.png" )

    composite << img
  end

  ## composite.save( "./btcwords/i/btcwords_#{offset}.png" )

  composite.save( "./tmp/btcwords_#{offset}.png" )
  # composite.zoom(4).save( "./tmp/btcwords_#{offset}@4x.png" )
end

puts "bye"


text:
require 'ordinals'
require 'pixelart'

##############################
#   d.i.y. alien (attribute) inscribes

inscribes =
{
 'base' => '81ec4177e7fce4e568cc1c14366fe29deb88b0f0841eb12d4f1d0638cca68201i0',

 ## note - double check and make sure
 ##            NOT to mix-up female and male attributes!!!

## female?
##  ['f/3d_glasses', '0182710716a6706aa1aadcdf06d6f33a4edac1c2f86d2c9f5e0f2d1ca0ec3ee9i0'],
##  ['f/bandana', '44d6266aea36dd0dddaa57498a5f3658ad16cf888089905e72d3683b0366e086i0'],
##  ['f/regular_shades', 'b1d98f466e0b2aec940f2981b9c67a5d862871b5fad677a4e674aac36090b038i0'],
## ['f/cap', 'c60989760670968c917f8c19a49a09d9f163345bd1a1c61e9700415f67a0e96ci0'],

## male??
  'm/pipe' =>         '92e7f48454546718f98103d7464d954033adbee21855f06584be06faa3e291ddi0',
  'm/cigarette' =>   'a01012b213ed425c5d4038bc36016f19f4f342ca052ff9bf6971672164e1a402i0',

  'm/nerd_glasses' => 'd61fc2a89ecc6ae65cf91cdfac9edc37fd60c38621dac211f3a70891ef79b69ai0',
  'm/vr'   =>         '680e2ee8cad86aa174b4f3373d733370c9a6fc4230b9708d520a0f6bcb8e72a6i0',
  'm/3d_glasses' =>  '56d3f4f661b2b4a9fc17755171d7cf4da74e570614b6b45de0cc87a809c3eb3ci0',
  'm/eye_mask'  =>     'fe4321178bd841e52fdeb72ce4456c5b7596c0d611b19da15ba75ec63b5314cai0',
  'm/regular_shades' => 'eddc1242f0fd290e130332e046897ad41dce1e7e112df48ecf2168e43172d383i0',
  'm/small_shades' => 'a2110fb4afaa29bc70bcfac445f750ecb5e81777e8d080be2d2b07eb030ba0ffi0',
  'm/horned_rim_glasses' => 'c1277df4b986067b2a3f006d717b7f6d042896840c8b592e5a8b9ff22444b08fi0',
  'm/bandana' => 'a6b4b81f69e8c217db24f0a71954195d67ced49a819b67a4daf9f3ca7fa1b971i0',
  'm/earring' => '06136a5b4fb585069ef6265a0fde3baf67ee914b9f784d2c951f3a8187800d54i0',
  'm/spots'  =>   '1355524a2aab576e069bac91227b0e52d227d65d84c5535377d3a0ea4e44d470i0',
  'm/knitted_cap' => '7c2fd41b52624ddb1ba11fe1c6d95475f2e42c4b53d6aaf6a16a09064acebe38i0',
  'm/headband'  => '83827ec13cb55a35fe3adca5acf67caf943c3bd6810f8fa893b067e8015c8f19i0',
  'm/tophat'  => '5b1e638c050318bec23f17b8b7758ccf13945e422516da6c722c67ae5ed4e26di0',
  'm/eye_patch' => '722dfdc90a67ff7eb892d13393a8a5b360b8a109f3d809600919684a600ff60ei0',
  'm/mohawk'  =>   '5ce9f89ad571e5380baa5b5ee387f08ea313421e7e54662b3899d411c39321ddi0',

  'm/hoodie'  => 'aab67a4269ca0bda649fe341bd88c862aba2e9bf6e0826b9dfa5c4ba8fe62c2di0',
  'm/cowboy_hat' => '5dcf96b13e5762d5a288d8bee36deb933fe192a55475199fe9a39ae29dd16853i0',
  'm/beanie'  =>  '0f473c9dcd14e3f43a6599b038d810eac16bc6394edcfcf6b32f8df992ab6791i0',
  'm/cap_forward' => '0bd902941392ea138adb7db30cecdf5bc09a92c80e3e1bc3ecdf3c2d0abf6631i0',

  'm/cap'  => '5760ce05009e94a750a7245cac994fa9ffd388eadc757929ac17737811455429i0',

  'm/dorag' => 'd32c50c23693a028e2381d6f756746a9ff684f2028edf694ab7b1b6cde78e2cdi0',
  'm/medical_mask' => '87d89d290ebde5d5b7aa75b4c8d0359515e25ea1542bc0646dc3f5b0b2fc55fdi0',
  'm/goldchain' => '8043604c7c96a5a43a97e251b246102ca40c0203431ff21bd26f23330dfa554ci0',
}

pp inscribes

inscribes.each_with_index do |(name,id), i|

  puts "==> #{i} - #{name} @ #{id}..."

   ## note: assume png - double check?

   path = "./tmp/aliens/#{name}.png"
   force = false  ## download & overwrite if exists

   if force == false && File.exist?( path )
      puts "  #{name} in cache"
   else
     content = Ordinals.content( id )
     pp content
     #=> #<Ordinals::Api::Content:0x000001a1352df938
     #      @data="RIFF\xF8\v\x00\x00WEBPVP8 \xEC\v\x00\x00...",
     #      @length=3072,
     #      @type="image/png"

     puts "data:"
     puts content.data

     write_blob( path, content.data )

     sleep( 0.5 )
   end
end

###
## assemble into spritesheet

attributes =
[
  'base',
  'm/mohawk',
  'm/spots',

  'm/bandana',
  'm/headband',
  'm/tophat',
  'm/cowboy_hat',
  'm/cap',
  'm/cap_forward',
  'm/knitted_cap',
  'm/beanie',
  'm/dorag',

  'm/nerd_glasses',
  'm/vr',
  'm/3d_glasses',
  'm/eye_mask',
  'm/regular_shades',
  'm/small_shades',
  'm/horned_rim_glasses',
  'm/eye_patch',

  'm/earring',
  'm/goldchain',

  'm/pipe',
  'm/cigarette',
  'm/medical_mask',

  'm/hoodie',
]

puts "  #{attributes.size} attribute(s)"

composite = ImageComposite.new( 10, 3, width: 24,
                                       height: 24 )

attributes.each do |name|
  path = "./tmp/aliens/#{name}.png"
  img = Image.read( path )
  composite << img
end

composite.save( "./tmp/aliens/spritesheet.png" )
# composite.zoom(4).save( "./tmp/aliens/spritesheet@4x.png" )
# composite.zoom(8).save( "./tmp/aliens/spritesheet@8x.png" )

###
## assemble generative array (jsom)

data = []
attributes.each do |name|
  id = inscribes[name]

  if id.nil?
    puts "!! ERROR - inscribe for >#{name}< not found; sorry"
    exit 1
  end

  data << id
end

puts "  #{data.size} id(s) in generative:"
pp data

write_json( "./tmp/aliens/generative.json", data )

puts "bye"


text:
require 'ordgen'

slug = 'diymaxibiz'
width  = 24
height = 24
max    = 100

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path =   "./#{slug}/spritesheet.png"

diymaxibiz  = Ordgen.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = diymaxibiz._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = diymaxibiz.generate( *g )

  composite << img
end

composite.save( "./tmp2/diymaxibiz.png" )
composite.zoom(4).save( "./tmp2/diymaxibiz@4x.png" )

puts "bye"


text:
require 'pixelart'

# slug = 'diypunks'
# slug = 'diycoolcats'

# slug = 'diyordibots'
# width  = 32
# height = 32

# slug = 'diypunks-v2'
# slug_spritesheet = 'diypunks'
# width  = 24
# height = 24

# slug = 'diypunks'
# width  = 24
# height = 24
# offset = 100

slug = 'diybirdies'
width  = 24
height = 24
offset = 200

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
recs = recs[offset, 100]
puts "   #{recs.size} record(s)"

spritesheet_path = if defined?( slug_spritesheet )
                     "./#{slug_spritesheet}/spritesheet.png"
                   else
                     "./#{slug}/spritesheet.png"
                   end

generator  = Orc721::Generator.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = generator._parse( rec['g'] )
  puts "==> no. #{offset+i}   g: #{rec['g']} - #{g.inspect}"
  img = generator.generate( *g )

  composite << img
end

outname =    if offset > 0
                "./tmp/#{slug}_#{offset}"
             else
                "./tmp/#{slug}"
             end

composite.save( "#{outname}.png" )
composite.zoom(4).save( "#{outname}@4x.png" )

puts "bye"


text:
require 'pixelart'

BLACK  = 0xff         ## e.g. rgba(0,0,0,255) - #000000ff

def pixels_to_numbers( pixels, colors: [BLACK] )
  nums = []
  pixels.each_with_index do |pixel, i|
      nums << i   if colors.include?( pixel )
  end
  nums
end

def image_to_ascii( img, colors: [BLACK] )
  buf = ""
  img.height.times do |y|
    img.width.times do |x|
      pixel = img[x,y]

      char = colors.include?( pixel ) ? '@' : '.'
      buf << "#{char} "   ## note: add extra (white)space
    end
    buf << "\n"
  end
  buf
end

####
## convert 150 punks (1-bit black & white)
punks = ImageComposite.read( './orange/1bitpunks.png',
                                 width: 24,
                                 height: 24 )

puts "  #{punks.size} punk(s)"
#=>  150 punk(s)

buf = ""

punks.size.times do |i|
  img = punks[i]
  pixels = img.pixels
  colors = pixels.uniq.size
  puts "==>  num #{i}   #{img.width}x#{img.height}  #{colors} color(s)..."

  ## nums = pixels_to_numbers( pixels )
  ## puts "    #{nums.size} / #{pixels.size}  pixels"
  ascii = image_to_ascii( img )

  ## add
  buf +=<<TXT
`
######
#  punk no. #{i+1}  - #{img.width}x#{img.height} px
#{ascii}
`,
TXT

end

puts buf

write_text( "./tmp2/designs-punks.js", buf )

####
#  convert starter images

starters = {
  'ordinal punk no. 1'  => Image.read( "./orange/opunk1.png" ),
  'smile face'  =>  Image.read( "./orange/smile.png" ),
  'punk'  =>  Image.read( "./orange/punk.png" ),
}

['cat1',
 'coffee',
 'knight1',
 'knight2',
 'shibainu1',
 'shibainu2',
].each do |name|
   starters[ name ] = Image.read( "./orange/#{name}.png" )
end

9.times do |num|
  name = "money#{num+1}"
  starters[ name ] = Image.read( "./orange/#{name}.png" )
end

27.times do |num|
  name = "animal#{num+1}"
  starters[ name ] = Image.read( "./orange/#{name}.png" )
end

buf = ""

starters.each_with_index do |(name, img), i|
  pixels = img.pixels
  colors = pixels.uniq.size
  puts "==>  num #{i}   #{img.width}x#{img.height}  #{colors} color(s)..."
  # nums = pixels_to_numbers( pixels )
  # puts "    #{nums.size} / #{pixels.size}  pixels"

  ascii = image_to_ascii( img )
  ## add
  buf +=<<TXT
`
######
#  #{name}  - #{img.width}x#{img.height} px
#{ascii}
`,
TXT

  img.zoom(8).save( "./tmp2/design#{i}@8x.png" )
end

write_text( "./tmp2/designs.js", buf )

####
## dump numbers
p pixels_to_numbers( Image.read( "./orange/opunk1.png" ).pixels )
puts
p pixels_to_numbers( Image.read( "./orange/smile.png" ).pixels )
puts

puts "bye"


text:
##
# to run use:
#
#  $ ruby sandbox/cache.rb

##
#  reformat cache to new format

require 'cocos'

cache_dir = "../ordinals.cache"

datasets = Dir.glob( "#{cache_dir}/inscriptionxxx/**.json" )
puts "  #{datasets.size} dataset(s)"
#=> 8803 dataset(s)

=begin
datasets.each_with_index do |path,i|
  print "#{i+1}/#{datasets.size} "
  data = read_json( path )

  ## break if i > 10

  buf = ''

  data.each do |k,v|
      next if ['preview', 'content'].include?( k )
      buf << "#{k.gsub( ' ', '-')}: #{v}\n"
  end

  puts
  basename = File.basename( path, File.extname( path))
  outpath = "#{cache_dir}/inscription/#{basename[0,2]}/#{basename[2..-1]}.meta.txt"

  puts "==> #{outpath}..."
  puts buf

  write_text( outpath, buf )
end
puts
puts
=end

contents = Dir.glob( "#{cache_dir}/inscriptionxxx/content/**.*" )
puts "  #{contents.size} content(s)"
#=>  7819 content(s)

contents.each_with_index do |path,i|
    ## break if i > 10

    blob = read_blob( path )
    basename = File.basename( path, File.extname( path))

    extname = nil
    meta = read_json( "#{cache_dir}/inscriptionxxx/#{basename}.json" )
    content_type  = meta['content type']
    content_length = meta['content length']
    puts "==> #{i+1}/#{contents.size} - >#{content_type}< #{content_length}..."
    if content_type.start_with?( 'text/plain' )
       extname = '.txt'
    elsif content_type.start_with?( 'application/json' )
       extname  = '.json'
    else
      puts "!! ERROR - unsupported content type; sorry"
      exit 1
    end

    outpath = "#{cache_dir}/inscription/#{basename[0,2]}/#{basename[2..-1]}#{extname}"

    puts "==> #{outpath}..."
    puts blob

    write_blob( outpath, blob )
end

puts "bye"


text:
require 'ordinals'
require 'pixelart'

cache_dir = '../../ordinals.cache/btc'

inscribes = {
# 0  Bonus - Bitcoin Orange
  '000-background_orange' => '189b02ffc8aac68a45102e9837a1ca92e422bf5544d9011a863626cf6b0abeeai0',

  # 1   Male 1
  '001-male_1' => '9d6afbc158e983735e563426981608ea63432619fab468c835322ea30a126c47i0',
# 2   Male 2
  '002-male_2' => '5ce8fa4973d47e5adc92be4587a02b12c553d202188ca0f2ee0c74356c368ea4i0',
# 3   Male 3
   '003-male_3' => '0f635374c2f60a7e34e2eb731bce23a5bc44d3a112ad02aceb23ea42606f6992i0',
# 4   Male 4
   '004-male_4' => '3e6e56b4fab6821bcd0c8baf590cf6217e7ec723f643abf809928cfd932fa08bi0',
# 5   Female 1
   '005-female_1' => '2cdcb5bfa63ca686543932c2214e4c6e04a856834ad516353bd5f1440bca5fd6i0',
# 6     Female 2
   '006-female_2' => '7fbfed7e38bbcaf851c2c4426b4c4ede9d09b6e6fd87a040403852681c7c19c2i0',
# 7   Female 3
   '007-female_3' => '5c8ab9ad57057e276f7b31e4e2a32d35e16c4fdda4b9070ddc57df23eb66518ai0',
# 8   Female 4
   '008-female_4' =>  'e7965554a5783f9e25ea0117a066dafe052cd5896c462bc2520a37f757f5e37fi0',
# 9   Zombie
   '009-zombie' =>  '1eb344bb1343de17a4bf5f8e11153d512362abb44458f6af0f6266025a8ac961i0',
# 10   Ape
  '010-ape'  => 'b36750a6b444e3815f0cbb50a36e0f1231b74ba930855b1e9067f907942f34fci0',
# 11   Alien
  '011-alien' => '81ec4177e7fce4e568cc1c14366fe29deb88b0f0841eb12d4f1d0638cca68201i0',
# 12    Rosy Cheeks (m)
   '012-rosy_cheeks' => 'fa1b6b749e5769f18298a54109d88bef08b2b7a851e993d2b95f39c80c27e9ffi0',
# 13   Luxurious Beard (m)
   '013-luxurious_beard' => '06ec577092baf39d78e4fceff71168f23687059d2a7046b5ef4012f5592a702ei0',
# 14    Clown Hair Green (m)
   '014-clown_hair_green' =>  '843a5269d45ed9864f70b821bef10c56302d31f0860c090ce5ae9bc39af84b57i0',
# 15     Mohawk Dark (m)
     '015-mohawk_dark' => '5ce9f89ad571e5380baa5b5ee387f08ea313421e7e54662b3899d411c39321ddi0',
# 16  Cowboy Hat (m)
   '016-cowboy_hat' => '5dcf96b13e5762d5a288d8bee36deb933fe192a55475199fe9a39ae29dd16853i0',
# 17   Mustache (m)
    '017-mustache' => '88c2a6594a4aed4d8d5cd6b5cafde85951942a1451f884eaa620e50245f56c2ci0',
# 18   Clown Nose (m)
    '018-clown_nose' => '00e698907dcb84c5ce3d1dbc22e88309aa7f288cff3d608c53ed3eea6af9bc04i0',
# 19    Cigarette (m)
    '019-cigarette' => 'a01012b213ed425c5d4038bc36016f19f4f342ca052ff9bf6971672164e1a402i0',
# 20   Nerd Glasses (m)
  '020-nerd_glasses' => 'd61fc2a89ecc6ae65cf91cdfac9edc37fd60c38621dac211f3a70891ef79b69ai0',
# 21   Regular Shades (m)
  '021-regular_shades' => 'eddc1242f0fd290e130332e046897ad41dce1e7e112df48ecf2168e43172d383i0',
# 22    Knitted Cap (m)
  '022-knitted_cap' => '7c2fd41b52624ddb1ba11fe1c6d95475f2e42c4b53d6aaf6a16a09064acebe38i0',
# 23    Shadow Beard (m)
   '023-shadow_beard' => 'ab01abac3faa712440d16d0a7739122340aa35f01d1423ec173ca1cbc7f9bcebi0',
# 24    Frown (m)
   '024-frown' => 'b65e4184c574fd6412a0a2e6ada97fb83a61343ea0bb238a3292277f3301093ai0',
# 25    Cap Forward (m)
   '025-cap_forward' => '0bd902941392ea138adb7db30cecdf5bc09a92c80e3e1bc3ecdf3c2d0abf6631i0',
# 26    Goat (m)
   '026-goat' => 'ed12dd62eb50048ea180f82bb6505abbece41156125bcfdfb1adfcfefd4bbbd8i0',
# 27     Mole (m)
   '027-mole' => '26dcfd2595fd5b705a9227664577fc1beae412c8842f2dcc23de40408ea6b83ci0',
# 28    Purple Hair (m)
   '028-purple_hair' => 'db0dd1952c0cdad6f1c7a0ffedd7c395a71818e73a33276709ab666f240034f2i0',
# 29    Small Shades (m)
  '029-small_shades' => 'a2110fb4afaa29bc70bcfac445f750ecb5e81777e8d080be2d2b07eb030ba0ffi0',
# 30      Shaved Head (m)
   '030-shaved_head' => '05fc9a15e179fa0765cfe2ed2f52112265377587cab9f227afc10100f0e72dd1i0',
# 31       Classic Shades (m)
   '031-classic_shades' => 'c36f12e655ab8af8bdd5c53a5bcb9eb758c2e33722f2e6cd932845ae93de143fi0',
# 32      Vape (m)
   '032-vape' => '7fc6c3e00f952b4337100eeaedf74acf383600e67e16f11f48fdf5ba27601545i0',
# 33     Silver Chain (m)
   '033-silver_chain' => 'cfc82aeb0ad4a25a43cba1bc76b44070a09017c94382986e0b3d55894d247571i0',
# 34   Smile (m)
   '034-smile' => 'f11caf409e98e30c74b79315cb1fe402cd613f3cb0266efa65b16cc5b5038629i0',
# 35    Big Shades (m)
   '035-big_shades' => '2e171b73b8837b55913b6be6004a9ad78be49778edf1642f826deac67ec7b18ai0',
# 36    Mohawk Thin (m)
  '036-mohawk_thin' => '209b83728679c0b3cda44301d482db34844dec3b7e873f58521d2f22b4820f5ci0',
# 37    Beanie (m)
  '037-beanie' => '0f473c9dcd14e3f43a6599b038d810eac16bc6394edcfcf6b32f8df992ab6791i0',
# 38  Cap (m)
  '038-cap' => '5760ce05009e94a750a7245cac994fa9ffd388eadc757929ac17737811455429i0',
# 39    Clown Eyes Green (m)
   '039-clown_eyes_green' => 'd9317eeee2c7f2f70dac1865c2c3a68a249898f09cb5c03f4723af48d7338009i0',
# 40    Normal Beard Black (m)
   '040-normal_beard_black' => '3bd7aa44570f9f7e51af070240fbb930d135310b67d408b719de11b6f20f4b54i0',
# 41   Medical Mask (m)
   '041-medical_mask' => '87d89d290ebde5d5b7aa75b4c8d0359515e25ea1542bc0646dc3f5b0b2fc55fdi0',
# 42   Normal Beard (m)
   '042-normal_beard' => 'efc6a4699c2cee6f305c72911df16a3dcf29fe75913b007607f175339485bf78i0',
# 43   VR (m)
   '043-vr' => '680e2ee8cad86aa174b4f3373d733370c9a6fc4230b9708d520a0f6bcb8e72a6i0',
# 44   Eye Patch (m)
   '044-eye_patch' =>  '722dfdc90a67ff7eb892d13393a8a5b360b8a109f3d809600919684a600ff60ei0',
# 45    Wild Hair (m)
   '045-wild_hair' => '9ec48f049d522a800cb880aa1b1adf807c9d3cf4e670bb4ebfeac49336b25993i0',
# 46     Top Hat (m)
   '046-top_hat' => '5b1e638c050318bec23f17b8b7758ccf13945e422516da6c722c67ae5ed4e26di0',
# 47    Bandana (m)
   '047-bandana' => 'a6b4b81f69e8c217db24f0a71954195d67ced49a819b67a4daf9f3ca7fa1b971i0',
# 48     Handlebars (m)
   '048-handlebars' => 'fad503c753b8da8c758f1bbc6fd60810397ae61eeffcc8a68964eae3f3ff46bei0',
# 49   Frumpy Hair (m)
  '049-frumpy_hair' => '43815da95ee418d61a29dd2afdefd8666549b8e23dfa0ceb4eda354466a8b3f7i0',
# 50    Crazy Hair (m)
   '050-crazy_hair'  => '78c1d952d2b2be42955931ed2718611879fa86c9b44b94801cdd5b7325a09642i0',
# 51    Police Cap (m)
   '051-police_cap' => 'cfc76dd5d7e5a5677f4d5cb142484385b71478aa4e5abe62be58ccd75125bd87i0',
# 52     Buck Teeth (m)
   '052-buck_teeth' => 'c4a74e192d70125886d39adb80ac8e321b61340446fa640c9fcd69d35aba0d0bi0',
# 53      Do-rag (m)
   '053-do-rag' => 'd32c50c23693a028e2381d6f756746a9ff684f2028edf694ab7b1b6cde78e2cdi0',
# 54    Front Beard (m)
   '054-front_beard' => 'b6c86723ef53a39cb1e40b315b167f1c9be0c841dfa2af31bb933c8164885166i0',
# 55    Spots (m)
   '055-spots' => '1355524a2aab576e069bac91227b0e52d227d65d84c5535377d3a0ea4e44d470i0',
# 56  Big Beard (m)
   '056-big_beard' => '8a4cb95de8d0928eb0fc20228cc678a2ae816ac92ff3a021569b6dc52a3b6d26i0',
# 57     Vampire Hair (m)
   '057-vampire_hair' => 'dc87795fdc400deda9bf8b18fda3281fa951d9ba1064608ea735c62193ecc0eei0',
# 58   Peak Spike (m)
    '058-peak_spike' => '9a75e2def0674d4ea8a49e80ba4474f5c932ae305b21eeb4fcc11bc1a495aa9di0',
# 59    Chinstrap (m)
    '059-chinstrap' => '618feda25d835adaf1e551883a014165a55c2a4ab4eb5e6e9bcd5cd18a5acc29i0',
# 60     Fedora (m)
    '060-fedora' => 'e6ebc3556df14856a42307337af8169f5924c36cefbc2516162956448963d302i0',
# 61    Earring (m)
   '061-earring' => '06136a5b4fb585069ef6265a0fde3baf67ee914b9f784d2c951f3a8187800d54i0',
# 62   Horned Rim Glasses (m)
   '062-horned_rim_glasses' => 'c1277df4b986067b2a3f006d717b7f6d042896840c8b592e5a8b9ff22444b08fi0',
# 63     Headband (m)
    '063-headband' => '83827ec13cb55a35fe3adca5acf67caf943c3bd6810f8fa893b067e8015c8f19i0',
# 64    Pipe (m)
    '064-pipe' => '92e7f48454546718f98103d7464d954033adbee21855f06584be06faa3e291ddi0',
# 65     Messy Hair (m)
    '065-messy_hair' => '397a319d4730b6ac665cc4dce0ae54aa2a6aa73e0b16462d35379756e04d8b5fi0',
# 66   Front Beard Dark (m)
  '066-front_beard_dark' => 'ad215dab98dad21577cbfe87c9d1d28790235e60ad281681932da33a38de3380i0',
# 67    Hoodie (m)
  '067-hoodie' =>  'aab67a4269ca0bda649fe341bd88c862aba2e9bf6e0826b9dfa5c4ba8fe62c2di0',
# 68     Gold Chain (m)
  '068-gold_chain' => '8043604c7c96a5a43a97e251b246102ca40c0203431ff21bd26f23330dfa554ci0',
# 69     Muttonchops (m)
   '069-muttonchops' => 'beea23b3036f39373e5eaadbedd6d0c196fdcd0a42b8a468ba67a176284d88e0i0',
# 70     Stringy Hair (m)
   '070-stringy_hair' => 'b7f370684042d2a77dba26128002c2a691b06acef01b5e274afa2588c6a3b8b1i0',
# 71  Eye Mask (m)
  '071-eye_mask' => 'fe4321178bd841e52fdeb72ce4456c5b7596c0d611b19da15ba75ec63b5314cai0',
# 72   3D Glasses (m)
  '072-3d_glasses' => '56d3f4f661b2b4a9fc17755171d7cf4da74e570614b6b45de0cc87a809c3eb3ci0',
# 73    Clown Eyes Blue (m)
   '073-clown_eyes_blue' => 'f9918b7b3b4df1c13ea73c2461f96b5e5d3b3986e6662ca90048728905c33644i0',
# 74     Mohawk (m)
  '074-mohawk' =>  '5ce9f89ad571e5380baa5b5ee387f08ea313421e7e54662b3899d411c39321ddi0',

# 75   Pilot Helmet (f)
  '075-pilot_helmet' => '67fb724fb5a68a211563d26db70847996171347d469ccda5e9a8413c45110c3bi0',
# 76    Tassle Hat (f)
   '076-tassle_hat' => 'c351991ae33651382e7e7eb6b53421010b52ea11a83fa8bc152ba7737d4c5b58i0',
# 77    Hot Lipstick (f)
   '077-hot_lipstick' => 'db16546971fbdeb7b2f21ee78a0328a1e82ce8f0d04bc93577e11ec31f498d53i0',
# 78     Blue Eye Shadow (f)
      '078-blue_eye_shadow' => 'f017611844cf5c520709e68cd9517b69c6e023ee1b8c279f53be2d802589362ei0',
# 79     Straight Hair Dark (f)
   '079-straight_hair_dark' => 'dfe116659af5477a9d8829458ddb7cced761a48432c9f213b3c02eb3e67ac15fi0',
# 80     Choker (f)
  '080-choker' =>  '31c3c1ace7c8863d36447357d87ba3144fbfbc8f742ce297cffb35b836d806dei0',
# 81    Crazy Hair (f)
   '081-crazy_hair' => '2afedce7036f463eab5a8e1c4ba67093282617b4bd09f12ae0eab472d93aa764i0',
# 82     Regular Shades (f)
   '082-regular_shades' => 'b1d98f466e0b2aec940f2981b9c67a5d862871b5fad677a4e674aac36090b038i0',
# 83    Wild Blonde (f)
   '083-wild_blonde' => '819fc98314103dae2a8e8dbf04c4ef1f5fc54d821f6f0d509eb11192e443ede5i0',
# 84    3D Glasses (f)
   '084-3d_glasses' => '0182710716a6706aa1aadcdf06d6f33a4edac1c2f86d2c9f5e0f2d1ca0ec3ee9i0',
# 85    Mole (f)
   '085-mole' => '69ce22bcdfa9d0748ba28c9a73e2e1b3370cc343db658ccb5abab4653e1a4c3ei0',
# 86   Wild White Hair (f)
  '086-wild_white_hair' => '5654174cfa3f55e85d8d2a5e5f35fd1bb309a856575b389bf19e9fde48e6688bi0',
# 87    Spots (f)
   '087-spots' => 'd885d809a41928f4780ba80a654e7b4cd8668c6f416aa5fcb85f8a4ce2570d51i0',
# 88    Frumpy Hair (f)
  '088-frumpy_hair' => 'e32b247314acc6e86db01937f1ae898e1bbb0eda642eb1167a9b10899948db13i0',
# 89    Nerd Glasses (f)
   '089-nerd_glasses' => 'b0e600e963663d2ee03593c0815980f0749c8a61eeefda0934abf9ca6ddcf2a5i0',
# 90   Tiara (f)
  '090-tiara' => '06729443440c4509d9022733a2eb9c747a1b42b11dae87832e64c339053ccc3ei0',
# 91  Orange Side (f)
   '091-orange_side' => '1e3bc62905a0e33616b8f963dce8ad0fcd3fea36006842559ee76bfd0257cfb0i0',
# 92    Red Mohawk (f)
   '092-red_mohawk' => '35ca91997926f23bbe18617fb6921a2002950881e365f3c3e408a22e926930f9i0',
# 93   Messy Hair (f)
   '093-messy_hair' => '97a7e1262423b72d43661162a5189336048a8a9cc774f7da0ab06a7ef2f9d33fi0',
# 94  Clown Eyes Blue (f)
   '094-clown_eyes_blue' => '2934660e11441092b9d417940b55287e61af159bc8a6cc1cb51000fa1652d6fai0',
# 95   Pipe (f)
   '095-pipe' => 'adc7696e06074d3a60599c2e4be79c5b2ad2303fe109bc04d904c17a0290960ci0',
# 96    Wild Hair (f)
  '096-wild_hair' => 'bd2cad95a86c1c0fb99f69ec590f188ebbf6c76be34733170c5df987829885a7i0',
# 97    Purple Eye Shadow (f)
   '097-purple_eye_shadow' => '70223379cf57ade54b3f00f3ac6491134907d7d3bcebbc10425a64d99dbc5aaai0',
# 98    Stringy Hair (f)
    '098-stringy_hair' => '7e017509d3c6680ffbd30c1f23b4fbfa164fe36688399e9e0bea367ef249698fi0',
# 99   Dark Hair (f)
  '099-dark_hair' => '0a11009d48145138ef83068a3a4b59e1563edc67b49a5db0b2aede0b011bb7a3i0',
# 100  Eye Patch (f)
   '100-eye_patch' => 'dc0422975f31d1eeca13c7fc6d09936c5d5217e5e8eaf94ef098a2d7b95ca19fi0',
# 101    Blonde Short (f)
   '101-blonde_short' => '02c4827b2c8e74b66f71c610bb371873fca6bd4b5f63adfaa155142a00f184aei0',
# 102    Classic Shades (f)
   '102-classic_shades' => 'f78db6fc25af28938730f3e821a4ef9d0bb74316acda28f7ab378dfd19f41ff9i0',
# 103   Eye Mask (f)
   '103-eye_mask' => '13df620523bd9b08d5dd63d974493c534d0d93fb830509bb347c39168ad9196ei0',
# 104     Clown Hair Green (f)
   '104-clown_hair_green' => '20a76349f16c4dbfd1aca99c2e457ce26a3be7160afd796560764bf1910d2ccfi0',
# 105   Cap (f)
   '105-cap' => 'c60989760670968c917f8c19a49a09d9f163345bd1a1c61e9700415f67a0e96ci0',
# 106   Medical Mask (f)
   '106-medical_mask' => 'be3bd4dd617160a8fda77bf745b0272020dba3223092ce08a049cd2c0838545fi0',
# 107   Bandana (f)
    '107-bandana' => '44d6266aea36dd0dddaa57498a5f3658ad16cf888089905e72d3683b0366e086i0',
# 108   Purple Lipstick (f)
    '108-purple_lipstick' => '02959b0904f61acda9419c2bb82ec3158fa97a0478d41d5150cfdc4e10a8b37bi0',
# 109    Clown Nose (f)
    '109-clown_nose' => '06b795f679e528e9fd0fd83ea7a322cff39bf131a0836bda5ac9c0f95876a768i0',
# 110     Headband (f)
   '110-headband' => 'ebca54ddbcd9da94b9bbcde11a1924becb3076d3500aa08170e2d147ae5c9700i0',
# 111    Pigtails (f)
  '111-pigtails' => '28031a5a4d1977b911727e832c7f2382f0fe2f510cdcda5eaab1eddd5b746b51i0',
# 112    Straight Hair Blonde (f)
  '112-straight_hair_blonde' => '5c540d6a565f4024abcaf0b1577f43cf2dcd5f30c3f3e61dcb144dc1c5123f82i0',
# 113   Knitted Cap (f)
  '113-knitted_cap' => '3daaa3ec7e365f8cd81a042b724513035a4b80c031c9b14f74bfedaa0150e924i0',
# 114   Clown Eyes Green (f)
   '114-clown_eyes_green' => '77d25521fcd8808742078dad2ae5f2cad9751187c72ee164cef72c95388f934di0',
# 115   Cigarette (f)
   '115-cigarette' =>  '35588d7e4cb81c5b4e56e7f9610a307766b543b91a7fb2a326e558d7555e6ce5i0',
# 116   Welding Goggles (f)
   '116-welding_goggles' => '5e0f701a232a83f1db21aaadb32f3495fd4296cdf1d2c406ec633ce2039e000bi0',
# 117   Mohawk Thin (f)
   '117-mohawk_thin' => '22f9268120bb2396e25e57020fb4e831bc64fdfb3c27935986a7fe7cc28c6ecei0',
# 118     Gold Chain (f)
    '118-gold_chain' => '82fe12aee4bfd8098406119be59ade336a5b5887a81e73c27cf5c6aaba9cf3fbi0',
# 119    VR (f)
    '119-vr' => 'b469a89182008c0e80aafc6dfc02a6cb76615ea42838a7ab989cf51ff1be8de1i0',
# 120   Vape (f)
    '120-vape' => '14462ca5a4d237976d85271792a7dc13f8a15c359e9113f8b5e4bd7d711cd7bbi0',
# 121   Pink With Hat (f)
   '121-pink_with_hat' => 'd0adcf57f93c917c0e8e37463d8389fef46067edb261f725a9c21acaf1848b61i0',
# 122     Blonde Bob (f)
   '122-blonde_bob' => '62ec589582651e49ed722241dab3bdb93fbd8ddf3fab3d891a30165126dddbcfi0',
# 123    Mohawk (f)
   '123-mohawk' => 'ede175a2f54c30680c9a30734977fb8955c24703cce8d833d45fd6239cb10e30i0',
# 124    Big Shades (f)
   '124-big_shades' => 'bf69af3d246da90d01a9acfe66b6bc3eb3365091f6eb6228186716d8c6ff17e8i0',
# 125    Earring (f)
    '125-earring' => '128d1e42f85e67d2a6b0c4c78e9ad47f7d66ed7699e77ddd0a4f0b8a21cdf736i0',
# 126    Green Eye Shadow (f)
    '126-green_eye_shadow' => 'b866e8f3f51c385a3ae27e65c5abe68e6086a6b74935b1b692de8587f5858148i0',
# 127    Straight Hair (f)
    '127-straight_hair' => '64c2890470ab4aea80c368b12fa0f416abc3da321b9e3c6940f211d9635db25di0',
# 128    Rosy Cheeks (f)
    '128-rosy_cheeks' => 'd555588738cda6bcf03b9b7b5f66968fe945bd293a714d652e262f80f6829c43i0',
# 129   Half Shaved (f)
    '129-half_shaved' => '2f5706f049c004c5dbefd4ef339de573ba41790572250b9a3558f16ac14702cdi0',
# 130     Mohawk Dark (f)
    '130-mohawk_dark' => 'd57f77b3eb7d5c4412bdc86deebc96a67517c27dcc6d6119fec1ba33f0367862i0',
# 131    Black Lipstick (f)
     '131-black_lipstick' => '2c4805e4015048cbdde22593c7b2c475889aa5b6bb433a17875892a0c507de28i0',
# 132   Horned Rim Glasses (f)
    '132-horned_rim_glasses' => '4c609e34152da749b68d5b281aba5d23e163d17283dd52dc77d4292dab8ebf77i0',
# 133   Silver Chain (f)
   '133-silver_chain' => 'e047590efef1e16b6e74a883835949b13b1921eb8587cee20dc4056c39be4b6ci0',
}

pp inscribes

inscribes.each_with_index do |(name,id), i|

    if id.empty?
       puts  "!! ERROR - required inscription id for >#{name}< missing"
       exit 1
    end

  puts "==> #{i} - #{name} @ #{id}..."

   ## note: assume png - double check?

   path = "./tmp/genesis/#{name}.png"
   force = false  ## download & overwrite if exists

   if force == false && File.exist?( path )
      puts "  #{name} content in cache"
   else
     content = Ordinals.content( id )
     pp content
     #=> #<Ordinals::Api::Content:0x000001a1352df938
     #      @data="RIFF\xF8\v\x00\x00WEBPVP8 \xEC\v\x00\x00...",
     #      @length=3072,
     #      @type="image/png"

     puts "data:"
     puts content.data

     write_blob( path, content.data )

     sleep( 0.5 )
   end

   ## get meta data for inscribe nums
   meta_path = "#{cache_dir}/#{id}.json"
   force = false  ## download & overwrite if exists

   if force == false && File.exist?( meta_path )
      puts "  #{name} meta in cache"
   else
      ## fetch and cache in cache
      meta = Ordinals.inscription( id )
      pp meta

      write_json( meta_path, meta )

      sleep( 0.5 )
   end
end

labels = [
 'Bonus! Bitcoin Orange Backgroud',
 'Male 1',
 'Male 2',
 'Male 3',
 'Male 4',
 'Female 1',
 'Female 2',
 'Female 3',
 'Female 4',
 'Zombie',
 'Ape',
 'Alien',
 'Rosy Cheeks (m)',
 'Luxurious Beard (m)',
 'Clown Hair Green (m)',
 'Mohawk Dark (m)',
 'Cowboy Hat (m)',
 'Mustache (m)',
 'Clown Nose (m)',
 'Cigarette (m)',
 'Nerd Glasses (m)',
 'Regular Shades (m)',
 'Knitted Cap (m)',
 'Shadow Beard (m)',
 'Frown (m)',
 'Cap Forward (m)',
 'Goat (m)',
 'Mole (m)',
 'Purple Hair (m)',
 'Small Shades (m)',
 'Shaved Head (m)',
 'Classic Shades (m)',
 'Vape (m)',
 'Silver Chain (m)',
 'Smile (m)',
 'Big Shades (m)',
 'Mohawk Thin (m)',
 'Beanie (m)',
 'Cap (m)',
 'Clown Eyes Green (m)',
 'Normal Beard Black (m)',
 'Medical Mask (m)',
 'Normal Beard (m)',
 'VR (m)',
 'Eye Patch (m)',
 'Wild Hair (m)',
 'Top Hat (m)',
 'Bandana (m)',
 'Handlebars (m)',
 'Frumpy Hair (m)',
 'Crazy Hair (m)',
 'Police Cap (m)',
 'Buck Teeth (m)',
 'Do-rag (m)',
 'Front Beard (m)',
 'Spots (m)',
 'Big Beard (m)',
 'Vampire Hair (m)',
 'Peak Spike (m)',
 'Chinstrap (m)',
 'Fedora (m)',
 'Earring (m)',
 'Horned Rim Glasses (m)',
 'Headband (m)',
 'Pipe (m)',
 'Messy Hair (m)',
 'Front Beard Dark (m)',
 'Hoodie (m)',
 'Gold Chain (m)',
 'Muttonchops (m)',
 'Stringy Hair (m)',
 'Eye Mask (m)',
 '3D Glasses (m)',
 'Clown Eyes Blue (m)',
 'Mohawk (m)',
 'Pilot Helmet (f)',
 'Tassle Hat (f)',
 'Hot Lipstick (f)',
 'Blue Eye Shadow (f)',
 'Straight Hair Dark (f)',
 'Choker (f)',
 'Crazy Hair (f)',
 'Regular Shades (f)',
 'Wild Blonde (f)',
 '3D Glasses (f)',
 'Mole (f)',
 'Wild White Hair (f)',
 'Spots (f)',
 'Frumpy Hair (f)',
 'Nerd Glasses (f)',
 'Tiara (f)',
 'Orange Side (f)',
 'Red Mohawk (f)',
 'Messy Hair (f)',
 'Clown Eyes Blue (f)',
 'Pipe (f)',
 'Wild Hair (f)',
 'Purple Eye Shadow (f)',
 'Stringy Hair (f)',
 'Dark Hair (f)',
 'Eye Patch (f)',
 'Blonde Short (f)',
 'Classic Shades (f)',
 'Eye Mask (f)',
 'Clown Hair Green (f)',
 'Cap (f)',
 'Medical Mask (f)',
 'Bandana (f)',
 'Purple Lipstick (f)',
 'Clown Nose (f)',
 'Headband (f)',
 'Pigtails (f)',
 'Straight Hair Blonde (f)',
 'Knitted Cap (f)',
 'Clown Eyes Green (f)',
 'Cigarette (f)',
 'Welding Goggles (f)',
 'Mohawk Thin (f)',
 'Gold Chain (f)',
 'VR (f)',
 'Vape (f)',
 'Pink With Hat (f)',
 'Blonde Bob (f)',
 'Mohawk (f)',
 'Big Shades (f)',
 'Earring (f)',
 'Green Eye Shadow (f)',
 'Straight Hair (f)',
 'Rosy Cheeks (f)',
 'Half Shaved (f)',
 'Mohawk Dark (f)',
 'Black Lipstick (f)',
 'Horned Rim Glasses (f)',
 'Silver Chain (f)',
]

##  "title": "Inscription 9992615",

TITLE_RX = /^Inscription (?<num>[0-9]+)$/i

def title_to_num( str )
   if m=TITLE_RX.match( str )
      m[:num].to_i(10)    ## use base 10
   else
     nil   ## not found - raise exception - why? why not?
   end
end

buf = <<TXT

In a Table

| No   |  24x24  | Name | Inscription №  |
|------|---------|------|----------------|
TXT

inscribes.each_with_index do |(name,id), i|
    meta_path = "#{cache_dir}/#{id}.json"

    meta = read_json( meta_path )

    num = title_to_num( meta['title'])

  buf << "| #{i} | ![](i/#{name}.png) |  #{labels[i]} | "
  buf << "[№ #{num}](https://ordinals.com/inscription/#{id}) |\n"
end

puts
puts buf
puts

ids = []
inscribes.each_with_index do |(name,id), i|
    ids << id
end

puts ids.join( "\n" )
puts

###
## assemble spritesheet
composite = ImageComposite.new( 10, 14, width: 24,
                                        height: 24 )

inscribes.each_with_index do |(name,id), i|
  path = "./tmp/genesis/#{name}.png"
  img = Image.read( path )
  composite << img
end

composite.save( "./tmp/genesis/spritesheet.png" )
# composite.zoom(4).save( "./tmp/genesis/spritesheet@4x.png" )
# composite.zoom(8).save( "./tmp/genesis/spritesheet@8x.png" )

puts "bye"


text:
require 'pixelart'

#######
#   collection (config) setup here ...

# slug = 'diypunks'
slug = 'diypunks-v2'
# slug = 'diycoolcats'
width  = 24
height = 24
max = 721
grid = [30,25]   ## 30 cols x 25 rows = 750

slug_spritesheet = 'diypunks'

###
#  start processing...

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s)"

# cut-down to max. limit
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path = if defined?( slug_spritesheet )
                     "./#{slug_spritesheet}/spritesheet.png"
                   else
                     "./#{slug}/spritesheet.png"
                   end

generator = Orc721::Generator.read( spritesheet_path,
                                       width:  width,
                                       height: height )

composite = ImageComposite.new( *grid, width: width,
                                       height: height )

recs.each_with_index do |rec,i|
  g = generator._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"

  img = generator.generate( *g )

  composite << img
end

outname =  "./tmp/#{slug}_max#{max}"

composite.save( "#{outname}.png" )
composite.zoom(4).save( "#{outname}@4x.png" )

puts "bye"


text:
require 'ordgen'

#######
#   collection (config) setup here ...

max = 721

###
#  start processing...
recs = read_csv( "./diycoolcats/mint.csv" )
puts "   #{recs.size} record(s)"

# cut-down to max. limit
recs = recs[0, max]
puts "   #{recs.size} record(s)"

diycoolcats = Ordgen.read( "./diycoolcats/spritesheet.png",
                             width:  24,
                             height: 24 )

## 30 cols x 25 rows = 750
composite = ImageComposite.new( 30,25, width: diycoolcats.width,
                                       height: diycoolcats.height )

recs.each_with_index do |rec,i|
  g = diycoolcats._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"

  composite << diycoolcats.generate( *g )
end

outname =  "./tmp2/diycoolcats_max#{max}"

composite.save( "#{outname}.png" )
composite.zoom(4).save( "#{outname}@4x.png" )

puts "bye"


text:
require 'ordgen'

slug = 'diyapes'
width  = 24
height = 24
max    = 100

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path =   "./docs/#{slug}/spritesheet.png"

diyapes  = Ordgen.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = diyapes._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = diyapes.generate( *g )

  composite << img
end

composite.save( "./tmp2/diyapes.png" )
composite.zoom(4).save( "./tmp2/diyapes@4x.png" )

puts "bye"


text:
require 'ordgen'

slug = 'diyaliens'
width  = 24
height = 24
max    = 100

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s) - total"

## cut down to first hundred
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path =   "./docs/#{slug}/spritesheet.png"

diyaliens  = Ordgen.read( spritesheet_path,
                                       width: width,
                                       height: height )

composite = ImageComposite.new( 10, 10, width: width,
                                        height: height )

recs.each_with_index do |rec,i|
  g = diyaliens._parse( rec['g'] )
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  img = diyaliens.generate( *g )

  composite << img
end

composite.save( "./tmp2/diyaliens.png" )
composite.zoom(4).save( "./tmp2/diyaliens@4x.png" )

puts "bye"


text:
require 'pixelart'

module Pixelart
  class Image
    def blackout( color='#ffffff' )
      color = Color.parse( color )

      img = Image.new( @img.width, @img.height )

      @img.width.times do |x|
        @img.height.times do |y|
          pixel = @img[x,y]

          img[x,y] = if [color, Color::TRANSPARENT].include?( pixel )    # transparent (0)
                         color ## change transparent to background color
                     else
                         0x000000ff  ## black - r/g/b/a (0,0,0,255)
                     end
      end
    end
    img
  end
  end  # class Image
  end # module Pixelart

BLACK  = 0xff         ## e.g. rgba(0,0,0,255) - #000000ff

def pixels_to_numbers( pixels, colors: [BLACK] )
  nums = []
  pixels.each_with_index do |pixel, i|
      nums << i   if colors.include?( pixel )
  end
  nums
end

##
## blackout
['monkey1',
 'monkey2',
 'monkey3',
 'monkey4',
 'monkey5',
 'monkey6',
 ]

[
 'gm',
 'heart1',
 'heart2',
 'heart3',
 'heart4',
 'smiley1',
 'smiley2',
 'smiley3',
 'smiley4',
 'smiley5',
 'smiley6',
 'smiley7',
]

['paper1',
 'paper2',
 'paper3',
 'paper4',
 'op45',
 'op55',
 'op93',
 'op95',
].each do |name|

   puts "==> #{name}..."

   img = Image.read( "./orange2/tmp/#{name}.png" )
   img = img.blackout

   img.save( "./orange2/#{name}.png" )
   orange = img.change_colors( { 0xff => 0xff9900ff,
                                 0xffffffff => 0, } )
   orange.save( "./orange2/tmp/orange-#{name}.png" )
   orange.zoom(4).save( "./orange2/tmp/orange-#{name}@4x.png" )
   orange.zoom(8).save( "./orange2/tmp/orange-#{name}@8x.png" )

   puts
   p pixels_to_numbers( img.pixels )
   puts
end

__END__

##
## blackout
['cat1',
 'coffee',
 'knight1',
 'knight2',
 'opunk1',
 'punk',
 'shibainu1',
 'shibainu2',
 'smile',
].each do |name|

   img = Image.read( "./orange/tmp/#{name}.png" )
   img = img.blackout

   img.save( "./orange/#{name}.png" )
   img.zoom(8).save( "./orange/tmp/#{name}@8x.png" )
end

## split money series into 1/1s
##  change to all white & black!

composite = ImageComposite.read( './orange/tmp/money.png',
                                 width: 24,
                                 height: 24 )

puts "  #{composite.size} tiles(s)"
#=>  150 punk(s)

composite.size.times do |i|
  puts "==> #{i+1} ..."
  tile = composite[i]

  ## convert all non-white to black
  colors = tile.pixels.uniq
  pp colors

  tile = tile.blackout
  puts "  blackout:"
  colors = tile.pixels.uniq
  pp colors

  tile.save( "./orange/money#{i+1}.png" )
  tile.zoom(8).save( "./orange/tmp/money#{i+1}8x.png" )
end

num = 0
[1,2,3].each do |vol|
  composite = ImageComposite.read( "./orange/tmp/animals#{vol}-18x18.png",
                                 width: 18,
                                 height: 18 )

puts "  #{composite.size} tiles(s)"
#=>  150 punk(s)

composite.size.times do |i|
  puts "==> #{num+1} ..."
  tile = composite[i]

  ## convert all non-white to black
  colors = tile.pixels.uniq
  pp colors

  tile = tile.blackout
  puts "  blackout:"
  colors = tile.pixels.uniq
  pp colors

  frame = Image.new( 24, 24, 0xffffffff )
  frame.compose!( tile, 3, 4 )

  frame.save( "./orange/animal#{num+1}.png" )
  frame.zoom(8).save( "./orange/tmp/animal#{num+1}@8x.png" )

  num += 1
end
end

puts "bye"


text:
require 'ordinals'
require 'pixelart'

##############################
#   d.i.y. martians (attribute) inscribes

inscribes =
{

 ## 7 base martians (aliens vol. 2)
 'orange'      =>  '0829dc471f8bb92a971dfdfb00a71c016b833c8f1d5f39dcb15aa5535d08fc15i0',
 'gold'        =>  '9482552ec759b76577b28923741eb4bfc7770cead528755bf8fa44196ae9318ci0',
 'cybergreen'  =>  '5b8eb4a05f13fffc49f824f457fb080b67e4fdc312fbbf2f804cef59e6d5fad2i0',
 'deepblue'    =>  '85e0efd6cc2801ab7e1fe28e23110441348ca40481599f880c571ff4f69f066fi0',
 'midnight'    =>  '7953ccb6614a41e7b4c4ed2a2b112b52feda387de92de2c1a314f03d5da41955i0',
 'magenta'     =>  '2f1219924cfa01f9816581e8a39e201f15e19ab447e852ff9b43b13fa7b0c75di0',
 'marsred'     =>  'e60f597ec41c50e823ea382c101dfc2f30c13a927222be3b73cedd88bd1b9237i0',

 'smile'       =>  '3459b14a4fcb7bce1df0465abc711b556caba6f7b42d4f925f1ddf830be47125i0',

 'lasereyes'  =>  '72fe7ebda802852f499dca865ec22ac43eacfcf4796d761969ae8358791e943ci0',
 'lasereyes-gold'  =>  '4db2e931b5cd489d8007d111d20ab97d84161b84c8f7ff3038e1afe79567b9afi0',
 'lasereyes-blue'  =>  '4869c9bb7cf23e68ad94da5b1e9de1feff1ebdcaf9a08fccca5f1887dd40e239i0',

  'nounie'  => 'a0d11e78978a9dd5f1d891b71f06bd2d411c08372eba1f23e8b0722474388130i0',  # red-ish (small)

  'noun1' => '2c2d812754b9374ffb699173da7f6d476af138a99906b66b8453cc4343305167i0', # red-ish
  'noun2' => '964c52312f1db9025695b181d5f631292d29bec63ff9587138a589cb5ff8c26di0', # blue-ish
  'noun3' => '545fd4d45d2f6d732d48accc082f72b67a00d19f88517320f814bf1fe827c816i0', # rgb

  'm/pipe' =>         '92e7f48454546718f98103d7464d954033adbee21855f06584be06faa3e291ddi0',
  'm/cigarette' =>   'a01012b213ed425c5d4038bc36016f19f4f342ca052ff9bf6971672164e1a402i0',

  'm/nerd_glasses' => 'd61fc2a89ecc6ae65cf91cdfac9edc37fd60c38621dac211f3a70891ef79b69ai0',
  'm/vr'   =>         '680e2ee8cad86aa174b4f3373d733370c9a6fc4230b9708d520a0f6bcb8e72a6i0',
  'm/3d_glasses' =>  '56d3f4f661b2b4a9fc17755171d7cf4da74e570614b6b45de0cc87a809c3eb3ci0',
  'm/eye_mask'  =>     'fe4321178bd841e52fdeb72ce4456c5b7596c0d611b19da15ba75ec63b5314cai0',
  'm/regular_shades' => 'eddc1242f0fd290e130332e046897ad41dce1e7e112df48ecf2168e43172d383i0',
  'm/small_shades' => 'a2110fb4afaa29bc70bcfac445f750ecb5e81777e8d080be2d2b07eb030ba0ffi0',
  'm/horned_rim_glasses' => 'c1277df4b986067b2a3f006d717b7f6d042896840c8b592e5a8b9ff22444b08fi0',
  'm/bandana' => 'a6b4b81f69e8c217db24f0a71954195d67ced49a819b67a4daf9f3ca7fa1b971i0',
  'm/earring' => '06136a5b4fb585069ef6265a0fde3baf67ee914b9f784d2c951f3a8187800d54i0',
  'm/spots'  =>   '1355524a2aab576e069bac91227b0e52d227d65d84c5535377d3a0ea4e44d470i0',
  'm/knitted_cap' => '7c2fd41b52624ddb1ba11fe1c6d95475f2e42c4b53d6aaf6a16a09064acebe38i0',
  'm/headband'  => '83827ec13cb55a35fe3adca5acf67caf943c3bd6810f8fa893b067e8015c8f19i0',
  'm/tophat'  => '5b1e638c050318bec23f17b8b7758ccf13945e422516da6c722c67ae5ed4e26di0',
  'm/eye_patch' => '722dfdc90a67ff7eb892d13393a8a5b360b8a109f3d809600919684a600ff60ei0',
  'm/mohawk'  =>   '5ce9f89ad571e5380baa5b5ee387f08ea313421e7e54662b3899d411c39321ddi0',

  'm/hoodie'  => 'aab67a4269ca0bda649fe341bd88c862aba2e9bf6e0826b9dfa5c4ba8fe62c2di0',
  'm/cowboy_hat' => '5dcf96b13e5762d5a288d8bee36deb933fe192a55475199fe9a39ae29dd16853i0',
  'm/beanie'  =>  '0f473c9dcd14e3f43a6599b038d810eac16bc6394edcfcf6b32f8df992ab6791i0',
  'm/cap_forward' => '0bd902941392ea138adb7db30cecdf5bc09a92c80e3e1bc3ecdf3c2d0abf6631i0',

  'm/cap'  => '5760ce05009e94a750a7245cac994fa9ffd388eadc757929ac17737811455429i0',

  'm/dorag' => 'd32c50c23693a028e2381d6f756746a9ff684f2028edf694ab7b1b6cde78e2cdi0',
  'm/medical_mask' => '87d89d290ebde5d5b7aa75b4c8d0359515e25ea1542bc0646dc3f5b0b2fc55fdi0',
  'm/goldchain' => '8043604c7c96a5a43a97e251b246102ca40c0203431ff21bd26f23330dfa554ci0',

   ## backgrounds
  'background_bitcoin-orange' => '189b02ffc8aac68a45102e9837a1ca92e422bf5544d9011a863626cf6b0abeeai0',
  'background_bitcoin-pattern' => '43e93e43f2dac75b141baaa5b08df440e0b6ec5755577a9554a7af6540447bb7i0',
  'background_red' => '39d774f7d7514371c88bc4f939346f6b23000c9892ac4ae8ea36c76694e3b842i0',
  'background_green' => 'b268b2acccd6b04680c2aa3130863ffbaa450f6870f100af678428cd07212ef6i0',
  'background_dollar-pattern' => 'ac810c9098681e100964166b7510d1ac371c147861b0ae2a862da3a8b8256037i0',
  'background_blue' => '4b9f880df07b072a4147a62acdd0881d024d14da6d84174db9b5ac555b71b346i0',
  'background_aqua' => '014ad6ed6297bc4ed624b2856e036c6bde115d51eb7200b14e3b3413ad53db08i0',
  'background_classic' => 'e139b5b0649186772cbf044bb8d3c5e43b77e3cf0472008ce2aaf52966c921eci0',
  'background_rainbow' => '6eb271ad3fdd15cc2ec34dda462e71aaa8a7ef7e306cfd189931ef37216a9c60i0',
  'background_ukraine' => '47cb34f1d73371df0b27ca0a259927fa80e2b2d9ee0e1d487fca5c9029b67b49i0',

}

pp inscribes

inscribes.each_with_index do |(name,id), i|

  puts "==> #{i} - #{name} @ #{id}..."

   ## note: assume png - double check?

   path = "./tmp/martians/#{name}.png"
   force = false  ## download & overwrite if exists

   if force == false && File.exist?( path )
      puts "  #{name} in cache"
   else
     content = Ordinals.content( id )
     pp content
     #=> #<Ordinals::Api::Content:0x000001a1352df938
     #      @data="RIFF\xF8\v\x00\x00WEBPVP8 \xEC\v\x00\x00...",
     #      @length=3072,
     #      @type="image/png"

     puts "data:"
     puts content.data

     write_blob( path, content.data )

     sleep( 0.5 )
   end
end

###
## assemble into spritesheet

attributes =
[
  'orange'    ,
  'gold'      ,
  'cybergreen',
  'deepblue',
  'midnight',
  'magenta',
  'marsred',

  'm/mohawk',
  'smile',         ## add smile up here - why?
  'm/spots',

  'm/bandana',
  'm/headband',
  'm/tophat',
  'm/cowboy_hat',
  'm/cap',
  'm/cap_forward',
  'm/knitted_cap',
  'm/beanie',
  'm/dorag',

  'm/nerd_glasses',
  'm/vr',
  'm/3d_glasses',
  'm/eye_mask',
  'm/regular_shades',
  'm/small_shades',
  'm/horned_rim_glasses',
  'm/eye_patch',

  'nounie',  # red-ish (small)
  'noun1',   # red-ish
  'noun2',   # blue-ish
  'noun3',   # rgb

  'lasereyes',
  'lasereyes-gold',
  'lasereyes-blue',

  'm/earring',
  'm/goldchain',

  'm/pipe',
  'm/cigarette',
  'm/medical_mask',

  'm/hoodie',

  'background_bitcoin-orange',
  'background_bitcoin-pattern',
  'background_red',
  'background_green',
  'background_dollar-pattern',
  'background_blue',
  'background_aqua',
  'background_classic',
  'background_rainbow',
  'background_ukraine',
]

puts "  #{attributes.size} attribute(s)"

composite = ImageComposite.new( 10, 5, width: 24,
                                       height: 24 )

attributes.each do |name|
  path = "./tmp/martians/#{name}.png"
  img = Image.read( path )
  composite << img
end

composite.save( "./tmp/martians/spritesheet.png" )
composite.zoom(4).save( "./tmp/martians/spritesheet@4x.png" )
composite.zoom(8).save( "./tmp/martians/spritesheet@8x.png" )

###
## assemble generative array (jsom)

data = []
attributes.each do |name|
  id = inscribes[name]

  if id.nil?
    puts "!! ERROR - inscribe for >#{name}< not found; sorry"
    exit 1
  end

  data << id
end

puts "  #{data.size} id(s) in generative:"
pp data

write_json( "./tmp/martians/generative.json", data )

puts "bye"


text:
require 'pixelart'

backgrounds = [
 'bitcoin-orange',
 'bitcoin-pattern',
 'red',
 'green',
 'dollar-pattern',
 'blue',
 'aqua',
 'classic',
 'rainbow',
 'ukraine',
]

base = [
 'orange',
 'gold',
 'cybergreen',
 'deepblue',
 'midnight',
 'magenta',
 'marsred',
]

lasereyes = [
 'lasereyes',
 'lasereyes-gold',
 'lasereyes-blue'
]

composite = ImageComposite.new( 7, 1, width: 24,
                                      height: 24 )

base.each do |name|
   composite << Image.read( "./martians/#{name}.png" )
end

composite.save( "./martians/tmp/martians.png" )
composite.zoom(4).save( "./martians/tmp/martians@4x.png" )

composite = ImageComposite.new( 3, 1, width: 24,
                                      height: 24 )

lasereyes.each do |attr_name|
  composite << Image.read( "./martians/#{attr_name}.png" )
end

composite.save( "./martians/tmp/lasereyes.png" )
composite.zoom(4).save( "./martians/tmp/lasereyes@4x.png" )

composite = ImageComposite.new( 7, 3, width: 24,
                                      height: 24 )

lasereyes.each do |attr_name|
   attr = Image.read( "./martians/#{attr_name}.png")
   base.each do |base_name|
   alien  = Image.read( "./martians/#{base_name}.png" )
      img = Image.new( 24, 24 )
      img.compose!( alien )
      img.compose!( attr  )
      composite << img
   end
end

composite.save( "./martians/tmp/martians-lasereyes.png" )
composite.zoom(4).save( "./martians/tmp/martians-lasereyes@4x.png" )

smile = Image.read( "./martians/smile.png" )

smile.zoom( 4 ).save( "./martians/tmp/smile@4x.png" )
smile.zoom( 8 ).save( "./martians/tmp/smile@8x.png" )

composite = ImageComposite.new( 7, 1, width: 24,
                                      height: 24 )

base.each do |name|
   img = Image.new( 24, 24 )
   img.compose!( Image.read( "./martians/#{name}.png" ))
   img.compose!( smile )

   composite << img
end

composite.save( "./martians/tmp/martians-smile.png" )
composite.zoom(4).save( "./martians/tmp/martians-smile@4x.png" )

noun    = Image.read( "./martians/noun-glasses.png" )
noun_xl = Image.read( "./martians/noun-glasses_xl.png" )

noun.zoom( 4 ).save( "./martians/tmp/noun-glasses@4x.png" )
noun.zoom( 8 ).save( "./martians/tmp/noun-glasses@8x.png" )

noun_xl.zoom( 4 ).save( "./martians/tmp/noun-glasses_xl@4x.png" )
noun_xl.zoom( 8 ).save( "./martians/tmp/noun-glasses_xl@8x.png" )

composite = ImageComposite.new( 2, 1, width: 24,
                                      height: 24 )

composite << noun
composite << noun_xl
composite.save( "./martians/tmp/noun-glasses.png" )
composite.zoom( 4 ).save( "./martians/tmp/noun-glasses@4x.png" )

composite = ImageComposite.new( 7, 2, width: 24,
                                      height: 24 )

base.each do |name|
   img = Image.new( 24, 24 )
   img.compose!( Image.read( "./martians/#{name}.png" ))
   img.compose!( noun )

   composite << img
end

base.each do |name|
   img = Image.new( 24, 24 )
   img.compose!( Image.read( "./martians/#{name}.png" ))
   img.compose!( noun_xl )

   composite << img
end

composite.save( "./martians/tmp/martians-noun.png" )
composite.zoom(4).save( "./martians/tmp/martians-noun@4x.png" )

composite = ImageComposite.new( 10, 1, width: 24,
                                      height: 24 )

backgrounds.each do |name|
   composite << Image.read( "./martians/backgrounds/#{name}.png" )
end

composite.save( "./martians/tmp/backgrounds.png" )
composite.zoom(4).save( "./martians/tmp/backgrounds@4x.png" )

composite = ImageComposite.new( 6, 5, width: 24,
                                      height: 24 )

3.times do |n|
   backgrounds.each_with_index do |name,m|
       img = Image.new( 24, 24 )
       img.compose!( Image.read( "./martians/backgrounds/#{name}.png" ))
       i = n*10+m
       base_name = base[ i % base.size ]
       img.compose!( Image.read( "./martians/#{base_name}.png"))

       row = i / 6

       if row == 2
         lasereyes_name = lasereyes[ i % lasereyes.size ]
         img.compose!( Image.read( "./martians/#{lasereyes_name}.png"))
       end

       img.compose!( smile )   if row == 3

       img.compose!( noun_xl )   if row == 4

       composite << img
   end
end

composite.save( "./martians/tmp/martians-backgrounds.png" )
composite.zoom(4).save( "./martians/tmp/martians-backgrounds@4x.png" )

#####
#

###
## assemble into spritesheet

attributes =
[
  'm/mohawk',
  smile,
  'm/spots',

  'm/bandana',
  'm/headband',
  'm/tophat',
  'm/cowboy_hat',
  'm/cap',
  'm/cap_forward',
  'm/knitted_cap',
  'm/beanie',
  'm/dorag',

  'm/nerd_glasses',
  'm/vr',
  'm/3d_glasses',
  'm/eye_mask',
  'm/regular_shades',
  'm/small_shades',
  'm/horned_rim_glasses',
  'm/eye_patch',

   noun,
   noun_xl,

  'm/earring',
  'm/goldchain',

  'm/pipe',
  'm/cigarette',
  'm/medical_mask',

  'm/hoodie',
]

composite = ImageComposite.new( 10, 5, width: 24,
                                       height: 24 )

base.each do |name|
   composite << Image.read( "./martians/#{name}.png" )
end

attributes.each do |attr|
   img = if attr.is_a?( String )
           Image.read( "./tmp/apes/#{attr}.png" )
         else  ### assume image already
            attr
         end
  composite << img
end

lasereyes.each do |name|
   composite << Image.read( "./martians/#{name}.png" )
 end

composite << Image.new( 24, 24 ) ## place holder 1
composite << Image.new( 24, 24 ) ## place holder 2

backgrounds.each do |name|
   composite << Image.read( "./martians/backgrounds/#{name}.png" )
end

composite.save( "./martians/tmp/spritesheet.png" )
composite.zoom(4).save( "./martians/tmp/spritesheet@4x.png" )
# composite.zoom(8).save( "./martians/tmp/spritesheet@8x.png" )

puts "bye"


text:
require 'pixelart'

slug             = 'diyordibots-v2'
slug_spritesheet = 'diyordibots'
width  = 32
height = 32
max = 999
grid = [40,25]   ## 40 cols x 25 rows = 1000

recs = read_csv( "./#{slug}/mint.csv" )
puts "   #{recs.size} record(s)"

# cut-down to max. limit
recs = recs[0, max]
puts "   #{recs.size} record(s)"

spritesheet_path = if defined?( slug_spritesheet )
                     "./#{slug_spritesheet}/spritesheet.png"
                   else
                     "./#{slug}/spritesheet.png"
                   end

spritesheet = ImageComposite.read( spritesheet_path,
                                      width: width,
                                      height: height )

composite = ImageComposite.new( *grid, width: width,
                                       height: height )

recs.each_with_index do |rec,i|
  img = Image.new( width, height )
  g = rec['g'].split( ' ' ).map {|v| v.to_i(10) }
  puts "==> no. #{i}   g: #{rec['g']} - #{g.inspect}"
  g.each do |num|
     img.compose!( spritesheet[ num ] )
  end

  composite << img
end

outname =  "./tmp/#{slug}_max#{max}"

composite.save( "#{outname}.png" )
composite.zoom(4).save( "#{outname}@4x.png" )

puts "bye"


text:
require 'pixelart'

##
## for r/g/b use
##  red       #EB0208
#  green     #1F882B
#  blue      #1C37EA

base = %w[
  punk1
  punk1b
  marc1b
  ape1b
  demon1
  demon1b
  frankenstein1
  frankenstein1b
  orc1
  orc1b
  alien1
  alien1b
  robot1
  robot1b
]

patterns = %w[
  punk2
  punk2b
  punk2c
  pattern2
  pattern2b
  pattern1
  pattern1b
]

eyes = %w[
  face

  m/smile
  m/frown
  m/spots
  m/bigbeard
  m/normalbeard
  m/chinstrap
  m/goat

  m/goldchain

  lasereyes-red
  lasereyes-green
  lasereyes-blue
  lasereyes2-red
  lasereyes2-green
  lasereyes2-blue

  noun-red
  noun-green
  noun-blue

  m/smallshades
  m/regularshades
  m/hearteyes
  m/3dglasses
  m/vr
]

accessories = %w[
  m/crazyhair
  m/frumpyhair
  m/messyhair
  m/mohawk
  m/peakspike
  m/orangeside
  m/clownhair
  m/wildhair1
  m/wildhair2

  m/bandana
  m/beanie
  m/wizardhat
  m/cap
  m/mcd
  m/capforward
  m/cowboyhat
  m/fedora
  m/headband
  m/beret
  m/knittedcap
  m/sombrero
  m/tophat
  m/unclesamhat
  m/footballhelmet
  m/libertycap
  m/crown
  m/saudi
  m/jew

  m/bubblegum
  m/cigarette
  m/pipe
  m/medicalmask

  m/bearhood
  m/froghood
  m/hoodie
]

## 1/1s
mores = %w[
  more1
  more2
  more3
  more4
  more5
]

backgrounds = %w[
 background-bitcoin-orange
 background-bitcoin-pattern
 background-dollar-pattern
 background-usa
 background-rainbow
 background-ukraine
]

# lasereyes
# lasereyes2
# background-red
# background-green
# background-blue

composite = ImageComposite.new( 10, 9, width: 24,
                                       height: 24 )

names = base + patterns + eyes + accessories + mores + backgrounds

names.each do |name|
   path = "./#{name}.png"
   puts "==> reading >#{path}<..."
   img = Image.read( path )
   composite << img
end

composite.save( "./tmp/spritesheet.png" )
composite.zoom(4).save( "./tmp/spritesheet@4x.png" )

puts "bye"


text:
!! ERROR(S) in  11027180 / ff157a25cf058cb780b16235cf63911d2332bdcb72ca39737daf0424c0070dffi0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[10,179,176,143]

   - json parse -- 859: unexpected token at '{"p":"orc-721","op":"mint","s":"diybirdies","g":[10,179,176,143]'

!! ERROR(S) in  11330707 / 829b776caa422213eeedf4b4a3e8dd179162f96f47952d9505cf9271faf6e8b0i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[43、199、187、126、213]

   - json parse -- 451: unexpected token at '、199、187、126、213]'

!! ERROR(S) in  11330713 / 95815d0a753f684adf3994cb5a0cf74337d64a90a2778821b3f89d852db4d669i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[90、175、211、213]

   - json parse -- 451: unexpected token at '、175、211、213]'

!! ERROR(S) in  11330714 / 61c00e541b718049a96079c3e4b20e6894b92f9dcdee61ba3d963da18c4f719di0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[8、152、201、216]

   - json parse -- 451: unexpected token at '、152、201、216]'

!! ERROR(S) in  11330715 / d843c32b85ef540fc23266a53ac19885cd26f023d90136de651d40f4375f7aedi0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[23、187、147、213]

   - json parse -- 451: unexpected token at '、187、147、213]'

!! ERROR(S) in  11330716 / 7de027bdfe6d0a51b275a05c692ebc3aa0f41b3f27cf587e27c8e4a2ad59b800i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[76、201、175、93、216]

   - json parse -- 451: unexpected token at '、201、175、93、216]'

!! ERROR(S) in  11330717 / 8858bb37ca95202e3379b37f84aacbb61f27315705a6669407d3bd5e6cba1609i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[81、201、143、96、219]

   - json parse -- 451: unexpected token at '、201、143、96、219]'

!! ERROR(S) in  11330718 / db2213741efdc270e3ca4e55fff4095f4205e268640970066ad8f3969fd5a532i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[83、161、219、96、184]

   - json parse -- 451: unexpected token at '、161、219、96、184]'

!! ERROR(S) in  11330719 / 8ad439b2aeef88a858432fe10988f47a537301d1fd069d5c528cdc481570dc43i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[4、201、175、103、216]

   - json parse -- 451: unexpected token at '、201、175、103、216]'

!! ERROR(S) in  11330720 / a7e01581daab2dd3f27312ebd569900611b0b73acb264f44e6640e56cfc3be53i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[17、201、175、99、213]

   - json parse -- 451: unexpected token at '、201、175、99、213]'

!! ERROR(S) in  11330721 / d02e785d079729b9ee4b43a10af96fcdd838fd8adc457685b339c8e142054557i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[62、201、175、99、213]

   - json parse -- 451: unexpected token at '、201、175、99、213]'

!! ERROR(S) in  11330722 / bc3e149e269303eb3eb88539ac6a7468fed1c62cf0ee76db7f1110a5add79e70i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[23、201、167、99、213]

   - json parse -- 451: unexpected token at '、201、167、99、213]'

!! ERROR(S) in  11330723 / a76e7814d75ba96e21524b9472ae2d10556027501f7cdcd087c93ff1758d8288i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[22、186、175、99、216]

   - json parse -- 451: unexpected token at '、186、175、99、216]'

!! ERROR(S) in  11330724 / 78d0cc1338a1356308fc38c23c293e0a2b9b1c098c9d68bbd22cdddb6640a19ei0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[17、194、167、96、216]

   - json parse -- 451: unexpected token at '、194、167、96、216]'

!! ERROR(S) in  11330725 / 4955ea29c589d9b2185e812ab1cf9c2de11d787d6768a6438cd546ff55314c76i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[25、202、167、107、219]

   - json parse -- 451: unexpected token at '、202、167、107、219]'

!! ERROR(S) in  11330726 / f0d0ef5c060ee5dd795b7d07f996bdba22f219cd793f4d37a26716550718cb85i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[25、201、176、102、216]

   - json parse -- 451: unexpected token at '、201、176、102、216]'

!! ERROR(S) in  11330727 / 45b0d38b97e8bebac39ffdff9793686b0de11e9b860b0c0292aad869d72e73a4i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[82、186、175、103、216]

   - json parse -- 451: unexpected token at '、186、175、103、216]'

!! ERROR(S) in  11330728 / a6ed3307c9a145e420ae64ae7587dfe0c3f6cd582a684a3af483f845fd7ec5b6i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[81、201、175、216、100]

   - json parse -- 451: unexpected token at '、201、175、216、100]'

!! ERROR(S) in  11330729 / f347312055b1562fc184d2f1023324bd4da9e4988baa818647faf9e14acc21bfi0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[17、167、201、101、213]

   - json parse -- 451: unexpected token at '、167、201、101、213]'

!! ERROR(S) in  11330730 / e7bbbcaf701b468f9e721d84f82b878d306467ca164d6844fe0a88061b418c5ei0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[82、201、175、197、216、96]

   - json parse -- 451: unexpected token at '、201、175、197、216、96]'

!! ERROR(S) in  11341577 / fdc9743f1f6cc5e3751478839c794ad97f918df9e9d28ffd5c7f8695b45f1044i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[0,172,241]}

   - protocol --  g no. 241 out-of-range 0-219 (220) in 'diybirdies' mint

!! ERROR(S) in  11484130 / 27fa855a8be18c0ea15f11afbfe3cd4c56905349ed848f4aedcb6116144efb8ei0:
{
	"p": "orc-721",
	"op": "mint",
	"s": "diybirdies",
	"g": [47, 211, 132, 13, 13, 6, 111]
}

   - json parse -- 451: unexpected token at ' 13, 6, 111]
}'

!! ERROR(S) in  11489654 / 2f2bdfde37067e579f556da030714267f3a8479c69efeb8e25ca626274fdc6dfi0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":"g":[89,95,122,196,219]}

   - json parse -- 859: unexpected token at '{"p":"orc-721","op":"mint","s":"diybirdies","g":"g":[89,95,122,196,219]}'

!! ERROR(S) in  11489655 / 3c1338056b5aba31ced130500c3afc0fa01c4d083a1873967d1df88ca349a9d0i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":"g":[86,95,149,201,219]}

   - json parse -- 859: unexpected token at '{"p":"orc-721","op":"mint","s":"diybirdies","g":"g":[86,95,149,201,219]}'

!! ERROR(S) in  11510229 / 7bf0286062d644758149898ff20edbc3f3db05ba4fca3b6be0ac97204fd5743ai0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[8,93,113,167,180.213]}

   - protocol format -- g no. 180.213 not an integer number; got type Float

!! ERROR(S) in  11510232 / e46a5583dfde55672c30fcb30d3e9c53b8a5a5e947af3d13ad28ebab0eea3421i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[92,105,162,167,184.214]}

   - protocol format -- g no. 184.214 not an integer number; got type Float

!! ERROR(S) in  11510245 / 7e325cc41a97485c0ea64235ef3f77fae3be26ee59fd2446bb1ad785874c72c6i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[91,102,153,168,178.213]}

   - protocol format -- g no. 178.213 not an integer number; got type Float

!! ERROR(S) in  11511780 / f197e6bde38181583e46fa79ab0f25bef67aff95019b70e18b36d6f2f31f27b9i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[81,98,147,172,189.219]}

   - protocol format -- g no. 189.219 not an integer number; got type Float

!! ERROR(S) in  11511783 / 59c2e8d87c5de0cabd6dc723cdb98af418e5f28290e5136b0c8b6ec89aca10d6i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[90,99,152,167,179.214]}

   - protocol format -- g no. 179.214 not an integer number; got type Float

!! ERROR(S) in  11517394 / 861e2ed396978e33a4153b9a5cd5f05e500e093e34247522971f7556a211cf4ai0:
{"p":"orc-721","op":"mint","s":"diybirdies","g":[0,170,241]}

   - protocol --  g no. 241 out-of-range 0-219 (220) in 'diybirdies' mint

!! ERROR(S) in  11624325 / 216fe4c648176ab70ae4bd2aa686a8342126255892aa093b384846551c0cc028i0:
{"p":"orc-721","op":"mint","s":"diybirdies","g": [91, 202, 197, 215, 169, 174]

   - json parse -- 859: unexpected token at '{"p":"orc-721","op":"mint","s":"diybirdies","g": [91, 202, 197, 215, 169, 174]'

!! ERROR(S) in  11867798 / bdd7ca44827c46ef35809b503506f3eb7e29e381a032d391e782bd4851e3c454i0:
{
    "p": "orc-721",
    "op": "mint",
    "s": "diybirdies",
    "g": [89 98 177 197 219]
}

   - json parse -- 451: unexpected token at '98 177 197 219]
}'

!! ERROR(S) in  11906809 / 96862867a118f8300935267e07f68f368b289ad5fc54301045f7c284436776b1i0:
{
    "p": "orc-721",
    "op": "mint",
    "s": "diybirdies",
    "g": [[88, 212, 145, 219]]
}

   - protocol format -- g no. [88, 212, 145, 219] not an integer number; got type Array


text:
# D.I.Y. Birdies (max. 721) Quick Notes & Commentary

deploy (& spritesheet) inscribes thanks to [@TheInscriptor](https://twitter.com/TheInscriptor), public domain ("do what you want") pixel art thanks to [@TheSkullCat](https://twitter.com/TheSkullCat)

> D.I.Y. Birdies are deployed!!
>
>  -- TheInscriptor, Saturday, June 10th, 2023

Disclaimer -   **No guarantees. Use at your own risk. Here be dragons.**

## Wen deploy? Wen mint?

> Q: DIY birdies sold out ser ?

ser, d.i.y. birdies is a free mint (max. limit 721) - first-come/first-serve -  for a rough mint inscribe count search for diybirdies e.g. -> https://unisat.io/search?q=diybirdies&type=text&p=1  as of now the count is 389 results  (incl. 20+ broken mints) ... do the math!

... drum roll please ...

... the world's 1st ultra-rare never-before-seen d.i.y. birdies in 4x ...

... genesis  - no. 0 ...  is this a bot birdie?

![](https://ordbase.github.io/num/11328459@4x.png)

... no. 1 ... a ultra-rare skeleton bone birdie

![](https://ordbase.github.io/num/11328460@4x.png)

. no. 2 ... a white birdie with pilot helmet - ready for take-off!

![](https://ordbase.github.io/num/11328461@4x.png)

... yes, you can ... d.i.y.

---

How to mint ORC-721 D.I.Y. Birdies collection (185/721 minted)
written / posted by [@TheInscriptor](https://twitter.com/TheInscriptor) (copy pasta from #generative-orc-721 discord)

Step 1 - Assemble your birdie here: <https://ordbase.github.io/generative-orc-721/diybirdies>

Step 2 - Copy the "g" array to following .json

``` json
{
    "p": "orc-721",
    "op": "mint",
    "s": "diybirdies",
    "g": []
}
```

Step 3 - Validate the json: <https://jsonlint.com>

Step 4 - Use: <https://looksordinal.com> -> IMPORTANT! - Check the image how to setup the mint

IMPORTANT! Keep the window open and focused after you make the BTC payment for inscription until all the transactions show up (you can mint more at once! Just add rows)

![](i/looksordinal.png)

---

> Q: Do we need to consider the [art] layers so we dont get messed up ones like punks?

yes, for best image results use this layers / number cheat sheet -> [diybirdies/meta.csv](meta.csv)  AND the recommendation is to always preview your d.i.y. birdies here ->  <https://ordbase.github.io/generative-orc-721/diybirdies>  - happy (free) minting.

> Q: How to see the birdies after inscripted?

 about the d.i.y. birdies images ... note: all images "indexed" and confirmed listed in ->  [diybirdies/mint.csv](mint.csv)  - you can reference / see online in 1x (24x24px) and 4x (96x96px) using this link formula ...

 in 1x ->  <https://ordbase.github.io/num/11328463.png>  and ...

![](https://ordbase.github.io/num/11328463.png)

.. in 4x ->  <https://ordbase.github.io/num/11328463@4x.png>  ...

![](https://ordbase.github.io/num/11328463@4x.png)

... change / fill in your inscribe no to see your d.i.y. birdie  (if "indexed").

the first d.i.y. birdies mints are now "indexed" (validated & confirmed) and you can see your image online in 1x or 4x ... change / fill-in the inscribe no./num in the link .. that's all.
bonus:    share the link here so we all can enjoy your d.i.y. birdie!

> Q: how can i find the broken ones to check if i didn't mint wrong?

if the mint inscribe got "indexed" and you think you got it wrong than find / check the broken mints in the diybirdies/error.txt log  - see [diybirdies/error.txt](error.txt)

More about indexing ...

... for any updates see the [diybirdies/mint.csv](mint.csv) list online and the [diybirdies/error.txt](error.txt).

## Wen market?

SOON!

##  D.I.Y. Bridie Background & Trivia

Who is the (pixel) artist?

this time the pixel art is not "hand-painted" by the punk's not dead workshop ...

... the artist is known as ...

... drum-roll please ...

TheSkullCat

... okkie ... i know ...

... here's the source used-> <https://github.com/TheSkullCat/Burds_Assets>

the pixel art license reads:

To be used with whatever your mom would approve of ...

> Permitted Use. Do what you want.
>
> Prohibited Use. No touching food with unwashed hands. No exchanging for drugs.

please respect ;-).

anyways - big thanks to TheSkullCat for sharing if ever this message will reach the artist.

ps: if anyone is on twitter maybe ping and thank the generous (pixel) artist - now getting the burds inscribed on bitcoin forever "rebranded" as d.i.y. birdies ->  <https://twitter.com/TheSkullCat>

Why Moonbirds!?

...  moonbirds collection  (on ethereum max. 10000) ... about US$300 million mint (and secondary)in the first two days ... top 2 in pixel art ... if i remember last time i checked ... officially cc0 (creative commons licensed - public domain dediction by Kevin Rose of Proof Collective - in retrospect - not on launch in april 2022 ...

... max. 10000 ... now max. 721  (AND inscribed "on-chain" on bitcoin)  ... do the math ;-).

... anyways ... back to pixel art ... the moonbirds format is in ...

... 42x42px   ... not sure if a play on 24x24px (reverse the numbers) or 42 as in the answer to everything .... anyways ... the  burds (a.k.a. birdies)  are the moonbirds redone "by hand" by TheSkullCat  in 24x24px  with some easter eggs added in for more fun ...    that's the trivia.

## Questions? Comments?

Please post in the #generative-orc-721 channel
in the ordinal punks discord.
For an invite
see <https://twitter.com/OrdinalPunks/status/1620230583711576068>.