Breaking News - Looking for the 100 Ordinal Punks collection inscribed into the bitcoin blockchain on February 9th, 2023? See 100 Ordinal Punks - The Free White Label Quick Starter Edition »
Q: Dear sir, how do I get rich in
bits-coinpunks?A: If we all buy
bits-coinpunks from one another at ever higher prices we'll all be rich beyond our wildest dreams.21 million bits-coin. 10 000 punks. Do the math.
Punks - The Free White Label Quick Starter Edition
Let's (re)create from zero / scratch a pixel-perfect copy of the Matt & John's® 10 000 punks collection (Anno 2017).
Yes, you can. Do-it-yourself (DIY) and
own 100% forever your home-made free clean-room copy
of the billion dollar (2400×2400) bitmap
that kicked-off
a trillion dollar get-rich-quick digital art
mania / bubble in 2021 -
selling "decentralized" blockchain tokens
database records
to ever greater fools at ever higher prices.
Inside the Magic Money Machine - Mint 10 000 Unique Punks from 11 Archtetypes 'n' 122 Attributes
Let's copy and (re)use all punk (building) blocks in the basic series (24×24):
11 Archetypes:
Male 1/2/3/4
,
Female 1/2/3/4
,
Zombie
,
Ape
,
Alien 
122 Attributes (by category and a-z):
- Hat -
Bandana (m/f)
,
Beanie (m)
,
Cap (m/f)
,
Cap Forward (m)
,
Cowboy Hat (m)
,
Do-rag (m)
,
Fedora (m)
,
Headband (m/f)
,
Hoodie (m)
,
Knitted Cap (m/f)
,
Pilot Helmet (f)
,
Police Cap (m)
,
Tassle Hat (f)
,
Tiara (f)
,
Top Hat (m)

- Hair -
Blonde Bob (f)
,
Blonde Short (f)
,
Clown Hair Green (m/f)
,
Crazy Hair (m/f)
,
Dark Hair (f)
,
Frumpy Hair (m/f)
,
Half Shaved (f)
,
Messy Hair (m/f)
,
Mohawk (m/f)
,
Mohawk Dark (m/f)
,
Mohawk Thin (m/f)
,
Orange Side (f)
,
Peak Spike (m)
,
Pigtails (f)
,
Pink With Hat (f)
,
Purple Hair (m)
,
Red Mohawk (f)
,
Shaved Head (m)
,
Straight Hair (f)
,
Straight Hair Blonde (f)
,
Straight Hair Dark (f)
,
Stringy Hair (m/f)
,
Vampire Hair (m)
,
Wild Blonde (f)
,
Wild Hair (m/f)
,
Wild White Hair (f)

- Eyes -
3D Glasses (m/f)
,
Big Shades (m/f)
,
Classic Shades (m/f)
,
Eye Mask (m/f)
,
Eye Patch (m/f)
,
Horned Rim Glasses (m/f)
,
Nerd Glasses (m/f)
,
Regular Shades (m/f)
,
Small Shades (m)
,
VR (m/f)
,
Welding Goggles (f)

- Eyes (Makeup) -
Blue Eye Shadow (f)
,
Clown Eyes Blue (m/f)
,
Clown Eyes Green (m/f)
,
Green Eye Shadow (f)
,
Purple Eye Shadow (f)

- Blemishes -
Mole (m/f)
,
Rosy Cheeks (m/f)
,
Spots (m/f)

- Nose -
Clown Nose (m/f)
, - Ears -
Earring (m/f)

- Mouth -
Buck Teeth (m)
,
Frown (m)
,
Smile (m)

- Mouth (Makeup) -
Black Lipstick (f)
,
Hot Lipstick (f)
,
Purple Lipstick (f)

- Mouth Prop -
Cigarette (m/f)
,
Medical Mask (m/f)
,
Pipe (m/f)
,
Vape (m/f)

- Beard -
Big Beard (m)
,
Chinstrap (m)
,
Front Beard (m)
,
Front Beard Dark (m)
,
Goat (m)
,
Handlebars (m)
,
Luxurious Beard (m)
,
Mustache (m)
,
Muttonchops (m)
,
Normal Beard (m)
,
Normal Beard Black (m)
,
Shadow Beard (m)

- Neck Accessory -
Choker (f)
,
Gold Chain (m/f)
,
Silver Chain (m/f)

(Source: Punk (Building) Blocks - Basic Series (24×24))
Let's wipe up a generate_punk
method that
pastes / composes together
the building blocks / attributes and returns
a ready-to-save image. Example:
# generate punk #0 punk = generate_punk( 'Female 2', 'Earring', 'Blonde Bob', 'Green Eye Shadow' ) punk.save( "./tmp/punk0.png" ) punk.zoom(20).save( "./tmp/punk0@20x.png" ) # generate punk #1 punk = generate_punk( 'Male 1', 'Smile', 'Mohawk' ) punk.save( "./tmp/punk1.png" ) punk.zoom(20).save( "./tmp/punk1@20x.png" )
Here we go - the billion dollar formula:
require 'pixelart' def normalize( str ) ## allow (ignore): ## space ( ), ## underscore (_), ## dash (-) str.downcase.gsub( /[ _-]/, '' ).strip end def generate_punk( *values, dir: "./basic" ) punk_type = values[0] attribute_names = values[1..-1] punk_type = normalize( punk_type ) path = "#{dir}/#{punk_type}.png" punk = Image.read( path ) m_or_f = if punk_type.index( 'female' ) 'f' else 'm' end attribute_names.each do |attribute_name| next if attribute_name.nil? || attribute_name.empty? ## note: skip nil/empty attributes attribute_name = normalize( attribute_name ) path = "#{dir}/#{m_or_f}/#{attribute_name}.png" attribute = Image.read( path ) punk.compose!( attribute ) end punk end # method generate
Let's test drive punk #0 and punk 1 (see above) and voila! In the original 24×24 format:
And 20x (480×480):
Note: If you use your own building blocks
make sure your type and attribute names
match the filenames (without the .png extension).
For the matching algorithm all names
get automatically downcased and all spaces deleted,
thus,
Male 1 will map to male1.png
and 3D Glasses to 3dglasses.png
and Knitted Cap to knittedcap.png
and so on.
Let's read-in all meta data records for all 10 000 punks. See the punks.csv dataset that reads:
type, attribute1, attribute2, attribute3, attribute4, attribute5, attribute6, attribute7
Female 2, Earring, Blonde Bob, Green Eye Shadow,,,,
Male 1, Smile, Mohawk,,,,,
Female 3, Wild Hair,,,,,,
Male 1, Wild Hair, Pipe, Nerd Glasses,,,,
Male 2, Goat, Earring, Wild Hair, Big Shades,,,
Female 2, Earring, Half Shaved, Purple Eye Shadow,,,,
Male 2, Do-rag,,,,,,
Female 2, Spots, Wild White Hair, Clown Eyes Blue,,,,
Male 1, Luxurious Beard, Messy Hair,,,,,
Male 2, Big Beard, Police Cap, Clown Nose,,,,
Female 1, Mohawk, Blue Eye Shadow,,,,,
Female 2, Black Lipstick, Straight Hair Dark, Clown Eyes Green,,,,
...
Let's try:
require 'csvreader' recs = CsvHash.read( './punks.csv' ) puts "#{recs.size} punk(s)" #=> 10 000 punk(s)
And to wrap up let's loop over all 10 000 punks and generate a 24×24 version and a 20x zoom, that is, 480×480. Let's go:
recs.each_with_index do |rec,i| puts "==> punk #{i}:" pp rec values = rec.values punk = generate_punk( *values ) name = "punk#{i}" punk.save( "./o/#{name}.png" ) punk.zoom(20).save( "./o/#{name}@20x.png" ) end
Yes, that's it.
In the /o directory you will now find
two images per punk - in the orginal format, that is, 24×24
and 20x, that is, 480×480 - and get:
o/
punk0.png
punk0@20x.png
punk1.png
punk1@20x.png
punk2.png
punk2@20x.png
punk3.png
punk3@20x.png
punk4.png
punk4@20x.png
punk5.png
punk5@20x.png
punk6.png
punk6@20x.png
punk7.png
punk7@20x.png
punk8.png
punk8@20x.png
...
Let's open up the first hundred punks, that is, punk0.png to punk99.png:
And let's have a looksie at the biggie 20x (480×480) versions:
and so on.
Bonus - Generate an All-In-One (2400×2400) Composite Image
Let's generate an all-in-one composite image holding the complete collection of 10 000 punks in a 100×100 grid.
punks = CompositeImage.new( 100, 100 ) recs.each_with_index do |rec,i| values = rec.values punk = generate_punk( *values ) punks << punk end punks.save( "./o/punks.png" )
Yes, that's it.
Open up punks.png to have a looksie.
Note: Only showing the first one hundred punks as a preview. Download punks.png ~800k for the full monty.
Questions? Comments?
Post them on the D.I.Y. Punk (Pixel) Art reddit. Thanks.






































































































