Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/cryptopunksnotdead/punks.whitelabel

punks - the free white label quick starter edition - (re)create from zero / scratch a pixel-perfect copy of the first Matt & John's® 10 000 punks collection (Anno 2017)
https://github.com/cryptopunksnotdead/punks.whitelabel

10000 24px 24x24 cryptopunks cryptotulips pixelart punkverse

Last synced: about 1 month ago
JSON representation

punks - the free white label quick starter edition - (re)create from zero / scratch a pixel-perfect copy of the first Matt & John's® 10 000 punks collection (Anno 2017)

Awesome Lists containing this project

README

        

---

**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 »**](https://github.com/ordinalpunks/ordinalpunks.starter)

---

> Q: Dear sir, how do I get rich in ~bits-coin~ punks?
>
> A: If we all buy ~bits-coin~ punks 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 ![](basic/male1.png)
![](basic/male2.png)
![](basic/male3.png)
![](basic/male4.png),
Female 1/2/3/4 ![](basic/female1.png)
![](basic/female2.png)
![](basic/female3.png)
![](basic/female4.png),
Zombie ![](basic/zombie.png),
Ape ![](basic/ape.png),
Alien ![](basic/alien.png)

122 Attributes (by category and a-z):
- Hat -
Bandana (m/f)
![](basic/m/bandana.png)
![](basic/f/bandana.png),
Beanie (m)
![](basic/m/beanie.png),
Cap (m/f)
![](basic/m/cap.png)
![](basic/f/cap.png),
Cap Forward (m)
![](basic/m/capforward.png),
Cowboy Hat (m)
![](basic/m/cowboyhat.png),
Do-rag (m)
![](basic/m/dorag.png),
Fedora (m)
![](basic/m/fedora.png),
Headband (m/f)
![](basic/m/headband.png)
![](basic/f/headband.png),
Hoodie (m)
![](basic/m/hoodie.png),
Knitted Cap (m/f)
![](basic/m/knittedcap.png)
![](basic/f/knittedcap.png),
Pilot Helmet (f)
![](basic/f/pilothelmet.png),
Police Cap (m)
![](basic/m/policecap.png),
Tassle Hat (f)
![](basic/f/tasslehat.png),
Tiara (f)
![](basic/f/tiara.png),
Top Hat (m)
![](basic/m/tophat.png)
- Hair -
Blonde Bob (f)
![](basic/f/blondebob.png),
Blonde Short (f)
![](basic/f/blondeshort.png),
Clown Hair Green (m/f)
![](basic/m/clownhairgreen.png)
![](basic/f/clownhairgreen.png),
Crazy Hair (m/f)
![](basic/m/crazyhair.png)
![](basic/f/crazyhair.png),
Dark Hair (f)
![](basic/f/darkhair.png),
Frumpy Hair (m/f)
![](basic/m/frumpyhair.png)
![](basic/f/frumpyhair.png),
Half Shaved (f)
![](basic/f/halfshaved.png),
Messy Hair (m/f)
![](basic/m/messyhair.png)
![](basic/f/messyhair.png),
Mohawk (m/f)
![](basic/m/mohawk.png)
![](basic/f/mohawk.png),
Mohawk Dark (m/f)
![](basic/m/mohawkdark.png)
![](basic/f/mohawkdark.png),
Mohawk Thin (m/f)
![](basic/m/mohawkthin.png)
![](basic/f/mohawkthin.png),
Orange Side (f)
![](basic/f/orangeside.png),
Peak Spike (m)
![](basic/m/peakspike.png),
Pigtails (f)
![](basic/f/pigtails.png),
Pink With Hat (f)
![](basic/f/pinkwithhat.png),
Purple Hair (m)
![](basic/m/purplehair.png),
Red Mohawk (f)
![](basic/f/redmohawk.png),
Shaved Head (m)
![](basic/m/shavedhead.png),
Straight Hair (f)
![](basic/f/straighthair.png),
Straight Hair Blonde (f)
![](basic/f/straighthairblonde.png),
Straight Hair Dark (f)
![](basic/f/straighthairdark.png),
Stringy Hair (m/f)
![](basic/m/stringyhair.png)
![](basic/f/stringyhair.png),
Vampire Hair (m)
![](basic/m/vampirehair.png),
Wild Blonde (f)
![](basic/f/wildblonde.png),
Wild Hair (m/f)
![](basic/m/wildhair.png)
![](basic/f/wildhair.png),
Wild White Hair (f)
![](basic/f/wildwhitehair.png)
- Eyes -
3D Glasses (m/f)
![](basic/m/3dglasses.png)
![](basic/f/3dglasses.png),
Big Shades (m/f)
![](basic/m/bigshades.png)
![](basic/f/bigshades.png),
Classic Shades (m/f)
![](basic/m/classicshades.png)
![](basic/f/classicshades.png),
Eye Mask (m/f)
![](basic/m/eyemask.png)
![](basic/f/eyemask.png),
Eye Patch (m/f)
![](basic/m/eyepatch.png)
![](basic/f/eyepatch.png),
Horned Rim Glasses (m/f)
![](basic/m/hornedrimglasses.png)
![](basic/f/hornedrimglasses.png),
Nerd Glasses (m/f)
![](basic/m/nerdglasses.png)
![](basic/f/nerdglasses.png),
Regular Shades (m/f)
![](basic/m/regularshades.png)
![](basic/f/regularshades.png),
Small Shades (m)
![](basic/m/smallshades.png),
VR (m/f)
![](basic/m/vr.png)
![](basic/f/vr.png),
Welding Goggles (f)
![](basic/f/weldinggoggles.png)
- Eyes (Makeup) -
Blue Eye Shadow (f)
![](basic/f/blueeyeshadow.png),
Clown Eyes Blue (m/f)
![](basic/m/clowneyesblue.png)
![](basic/f/clowneyesblue.png),
Clown Eyes Green (m/f)
![](basic/m/clowneyesgreen.png)
![](basic/f/clowneyesgreen.png),
Green Eye Shadow (f)
![](basic/f/greeneyeshadow.png),
Purple Eye Shadow (f)
![](basic/f/purpleeyeshadow.png)
- Blemishes -
Mole (m/f)
![](basic/m/mole.png)
![](basic/f/mole.png),
Rosy Cheeks (m/f)
![](basic/m/rosycheeks.png)
![](basic/f/rosycheeks.png),
Spots (m/f)
![](basic/m/spots.png)
![](basic/f/spots.png)
- Nose -
Clown Nose (m/f)
![](basic/m/clownnose.png)
![](basic/f/clownnose.png),
- Ears -
Earring (m/f)
![](basic/m/earring.png)
![](basic/f/earring.png)
- Mouth -
Buck Teeth (m)
![](basic/m/buckteeth.png),
Frown (m)
![](basic/m/frown.png),
Smile (m)
![](basic/m/smile.png)
- Mouth (Makeup) -
Black Lipstick (f)
![](basic/f/blacklipstick.png),
Hot Lipstick (f)
![](basic/f/hotlipstick.png),
Purple Lipstick (f)
![](basic/f/purplelipstick.png)
- Mouth Prop -
Cigarette (m/f)
![](basic/m/cigarette.png)
![](basic/f/cigarette.png),
Medical Mask (m/f)
![](basic/m/medicalmask.png)
![](basic/f/medicalmask.png),
Pipe (m/f)
![](basic/m/pipe.png)
![](basic/f/pipe.png),
Vape (m/f)
![](basic/m/vape.png)
![](basic/f/vape.png)
- Beard -
Big Beard (m)
![](basic/m/bigbeard.png),
Chinstrap (m)
![](basic/m/chinstrap.png),
Front Beard (m)
![](basic/m/frontbeard.png),
Front Beard Dark (m)
![](basic/m/frontbearddark.png),
Goat (m)
![](basic/m/goat.png),
Handlebars (m)
![](basic/m/handlebars.png),
Luxurious Beard (m)
![](basic/m/luxuriousbeard.png),
Mustache (m)
![](basic/m/mustache.png),
Muttonchops (m)
![](basic/m/muttonchops.png),
Normal Beard (m)
![](basic/m/normalbeard.png),
Normal Beard Black (m)
![](basic/m/normalbeardblack.png),
Shadow Beard (m)
![](basic/m/shadowbeard.png)
- Neck Accessory -
Choker (f)
![](basic/f/choker.png),
Gold Chain (m/f)
![](basic/m/goldchain.png)
![](basic/f/goldchain.png),
Silver Chain (m/f)
![](basic/m/silverchain.png)
![](basic/f/silverchain.png)

(Source: [Punk (Building) Blocks - Basic Series (24×24)](https://github.com/cryptopunksnotdead/punks.blocks#basic-punk-series-2424))

Let's wipe up a `generate_punk`
method that
pastes / composes together
the building blocks / attributes and returns
a ready-to-save image. Example:

``` ruby
# generate punk #0
punk = generate_punk( 'Female 2', 'Earring', 'Blonde Bob', 'Green Eye Shadow' )
punk.save( "./tmp/punk0.png" )
punk.zoom(20).save( "./tmp/[email protected]" )

# generate punk #1
punk = generate_punk( 'Male 1', 'Smile', 'Mohawk' )
punk.save( "./tmp/punk1.png" )
punk.zoom(20).save( "./tmp/[email protected]" )
```

Here we go - the billion dollar formula:

``` ruby
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:

![](i/punk0.png)
![](i/punk1.png)

And 20x (480×480):

![](i/[email protected])
![](i/[email protected])

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` ![](basic/male1.png)
and `3D Glasses` to `3dglasses.png` ![](basic/m/3dglasses.png)
and `Knitted Cap` to `knittedcap.png` ![](basic/m/knittedcap.png)
and so on.

Let's read-in all meta data records for all 10 000 punks.
See the [punks.csv](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:

``` ruby
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:

``` ruby
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
[email protected]
punk1.png
[email protected]
punk2.png
[email protected]
punk3.png
[email protected]
punk4.png
[email protected]
punk5.png
[email protected]
punk6.png
[email protected]
punk7.png
[email protected]
punk8.png
[email protected]
...
```

Let's open up the first hundred punks, that is, `punk0.png` to `punk99.png`:

![](i/punk0.png)
![](i/punk1.png)
![](i/punk2.png)
![](i/punk3.png)
![](i/punk4.png)
![](i/punk5.png)
![](i/punk6.png)
![](i/punk7.png)
![](i/punk8.png)
![](i/punk9.png)
![](i/punk10.png)
![](i/punk11.png)
![](i/punk12.png)
![](i/punk13.png)
![](i/punk14.png)
![](i/punk15.png)
![](i/punk16.png)
![](i/punk17.png)
![](i/punk18.png)
![](i/punk19.png)
![](i/punk20.png)
![](i/punk21.png)
![](i/punk22.png)
![](i/punk23.png)
![](i/punk24.png)
![](i/punk25.png)
![](i/punk26.png)
![](i/punk27.png)
![](i/punk28.png)
![](i/punk29.png)
![](i/punk30.png)
![](i/punk31.png)
![](i/punk32.png)
![](i/punk33.png)
![](i/punk34.png)
![](i/punk35.png)
![](i/punk36.png)
![](i/punk37.png)
![](i/punk38.png)
![](i/punk39.png)
![](i/punk40.png)
![](i/punk41.png)
![](i/punk42.png)
![](i/punk43.png)
![](i/punk44.png)
![](i/punk45.png)
![](i/punk46.png)
![](i/punk47.png)
![](i/punk48.png)
![](i/punk49.png)
![](i/punk50.png)
![](i/punk51.png)
![](i/punk52.png)
![](i/punk53.png)
![](i/punk54.png)
![](i/punk55.png)
![](i/punk56.png)
![](i/punk57.png)
![](i/punk58.png)
![](i/punk59.png)
![](i/punk60.png)
![](i/punk61.png)
![](i/punk62.png)
![](i/punk63.png)
![](i/punk64.png)
![](i/punk65.png)
![](i/punk66.png)
![](i/punk67.png)
![](i/punk68.png)
![](i/punk69.png)
![](i/punk70.png)
![](i/punk71.png)
![](i/punk72.png)
![](i/punk73.png)
![](i/punk74.png)
![](i/punk75.png)
![](i/punk76.png)
![](i/punk77.png)
![](i/punk78.png)
![](i/punk79.png)
![](i/punk80.png)
![](i/punk81.png)
![](i/punk82.png)
![](i/punk83.png)
![](i/punk84.png)
![](i/punk85.png)
![](i/punk86.png)
![](i/punk87.png)
![](i/punk88.png)
![](i/punk89.png)
![](i/punk90.png)
![](i/punk91.png)
![](i/punk92.png)
![](i/punk93.png)
![](i/punk94.png)
![](i/punk95.png)
![](i/punk96.png)
![](i/punk97.png)
![](i/punk98.png)
![](i/punk99.png)

And let's have a looksie at the biggie 20x (480×480) versions:

![](i/[email protected])
![](i/[email protected])

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.

``` ruby
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.

![](i/punks-preview.png)

Note: Only showing the first one hundred punks as a preview.
Download [**punks.png**](i/punks.png) ~800k for the full monty.

## Questions? Comments?

Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.