{"id":21585421,"url":"https://github.com/cryptopunksnotdead/lets-go-programming-cryptopunks","last_synced_at":"2025-04-10T20:07:55.643Z","repository":{"id":180836553,"uuid":"93167832","full_name":"cryptopunksnotdead/lets-go-programming-cryptopunks","owner":"cryptopunksnotdead","description":"Let's Go! Programming (Crypto) Pixel Punk Profile Pictures \u0026 (Generative) Art with Go - Step-by-Step Book / Guide Inside Unique 24×24 Pixel Art on the Blockchain...","archived":false,"fork":false,"pushed_at":"2022-10-27T15:47:36.000Z","size":1375,"stargazers_count":34,"open_issues_count":0,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-24T17:52:42.617Z","etag":null,"topics":["24px","artbase","cryptopunks","pixelart","punkverse"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cryptopunksnotdead.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-06-02T13:24:55.000Z","updated_at":"2024-03-25T21:58:23.000Z","dependencies_parsed_at":"2023-07-13T03:00:00.040Z","dependency_job_id":null,"html_url":"https://github.com/cryptopunksnotdead/lets-go-programming-cryptopunks","commit_stats":null,"previous_names":["cryptopunksnotdead/lets-go-programming-cryptopunks"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryptopunksnotdead%2Flets-go-programming-cryptopunks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryptopunksnotdead%2Flets-go-programming-cryptopunks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryptopunksnotdead%2Flets-go-programming-cryptopunks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryptopunksnotdead%2Flets-go-programming-cryptopunks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cryptopunksnotdead","download_url":"https://codeload.github.com/cryptopunksnotdead/lets-go-programming-cryptopunks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248288347,"owners_count":21078903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["24px","artbase","cryptopunks","pixelart","punkverse"],"created_at":"2024-11-24T15:10:38.130Z","updated_at":"2025-04-10T20:07:55.623Z","avatar_url":"https://github.com/cryptopunksnotdead.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# Let's Go! Programming (Crypto) Pixel Punk Profile Pictures \u0026 (Generative) Art with Go - Step-by-Step Book / Guide\n\n_Inside Unique 24×24 Pixel Art on the Blockchain..._\n\nby [Gerald Bauer](https://github.com/geraldb), et al\n\n\n\n\n# 1\n\n## Do-It-Yourself (DIY) - Yes, You Can! - Mint Your Own Punks in Original 24x24 Pixel Format or With 2X / 4X / 8X Zoom\n\n\n### Step 0 -  Download a punks all-in-one composite image / collection\n\n\nOne time / first time only - Download\na punks pixel art collection\nfrom the\n[Awesome 24px Downloads - Free Pixel Art Collections in the 24x24 Format](https://github.com/cryptopunksnotdead/awesome-24px) page.\n\nLet's try the 1000 More Punks\ncollection\nin a single all-in-one 600×960px image (~180 kb) for free.\nSee ![](i/morepunks-strip.png) [`morepunks.png` »](https://github.com/cryptopunksnotdead/awesome-24px/blob/master/collection/morepunks.png)\n\n\n\nLet's create a program to mint (more) punk pixel art images.\nLet's (re)use\nthe pixelart package\nfrom the [learn pixel art org](https://github.com/learnpixelart/pixelart.go).\n\n\n\n### Step 1 -  Read punk composite image\n\n\n``` go\npackage main\n\n\nimport (\n  \"fmt\"\n  \"github.com/learnpixelart/pixelart.go/pixelart\"\n)\n\n\nfunc main() {\n\n  fmt.Printf( \"Hello, Pixel Art v%s!\\n\", pixelart.Version )\n\n  path     := \"./morepunks.png\"\n  tileSize := pixelart.Point{24, 24}\n  punks    := pixelart.ReadImageComposite( path, \u0026tileSize )\n\n  fmt.Println( punks.Bounds() )\n  //=\u003e (0,0)-(600,960)\n}\n```\n\n\n### Step 2 - Start minting\n\nNote: By default punks get saved in the original 24x24 pixel format\nand the first punk starts at index zero, that is, `0`.\nrunning up to 999.\n\nLet's mint punk #0, #18, #40, and #88.\nAdd inside `func main()`:\n\n\n``` go\npunk := punks.Tile( 0 )\nfmt.Println( punk.Bounds() )\n//=\u003e (0,0)-(24,24)\n\npunk.Save( \"./morepunk0.png\" )\n\n\npunks.Tile( 18 ).Save( \"./morepunk18.png\" )\npunks.Tile( 40 ).Save( \"./morepunk40.png\" )\npunks.Tile( 88 ).Save( \"./morepunk88.png\" )\n```\n\nAnd voila!\n\n![](i/morepunk0.png)\n![](i/morepunk18.png)\n![](i/morepunk40.png)\n![](i/morepunk88.png)\n\n\nLet's change the zoom factor:\n\n``` go\npunks.Tile( 0 ).Zoom( 4 ).Save( \"./morepunk0@4x.png\" )\npunks.Tile( 18 ).Zoom( 4 ).Save( \"./morepunk18@4x.png\" )\npunks.Tile( 40 ).Zoom( 4 ).Save( \"./morepunk40@4x.png\" )\npunks.Tile( 88 ).Zoom( 4 ).Save( \"./morepunk88@4x.png\" )\n```\n\nAnd voila in 4x!\n\n![](i/morepunk0@4x.png)\n![](i/morepunk18@4x.png)\n![](i/morepunk40@4x.png)\n![](i/morepunk88@4x.png)\n\n\n\nProof-of the pudding.\nIf you want to run the ready-made sample\nprogram in [**`01_tile/`**](01_tile) yourself try:\n\n- Generate a go module (`go.mod`)\n- Add the pixelart package via go get to `go.mod`\n- Run the code\n\n```\n$ cd 01_tile\n$ go mod init example.com/01_tile\n$ go get github.com/learnpixelart/pixelart.go/pixelart\n$ go run main.go\n```\n\n\n\n\n\nLet's try with the classic gray-ish\nbackground in red/green/blue (rgb) as a hexstring `#638596`:\n\n\n``` go\npunks.Tile( 0 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./morepunk0_(grayish)@4x.png\" )\npunks.Tile( 18 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./morepunk18_(grayish)@4x.png\" )\npunks.Tile( 40 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./morepunk40_(grayish)@4x.png\" )\npunks.Tile( 88 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./morepunk88_(grayish)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/morepunk0_(grayish)@4x.png)\n![](i/morepunk18_(grayish)@4x.png)\n![](i/morepunk40_(grayish)@4x.png)\n![](i/morepunk88_(grayish)@4x.png)\n\n\n\n\nPhilip! Phree the Phunks!\nLet's try to flip vertically, that is, mirror, the punk images - turning right-looking punks into left-looking.\n\n\n``` go\npunks.Tile( 0 ).Background( \"#638596\" ).Mirror().Zoom( 4 ).Save( \"./morephunk0_(grayish)@4x.png\" )\npunks.Tile( 18 ).Background( \"#638596\" ).Mirror().Zoom( 4 ).Save( \"./morephunk18_(grayish)@4x.png\" )\npunks.Tile( 40 ).Background( \"#638596\" ).Mirror().Zoom( 4 ).Save( \"./morephunk40_(grayish)@4x.png\" )\npunks.Tile( 88 ).Background( \"#638596\" ).Mirror().Zoom( 4 ).Save( \"./morephunk88_(grayish)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/morephunk0_(grayish)@4x.png)\n![](i/morephunk18_(grayish)@4x.png)\n![](i/morephunk40_(grayish)@4x.png)\n![](i/morephunk88_(grayish)@4x.png)\n\n\nAnd so on. Happy miniting.\n\n\n\n### Bonus - Glory to Ukraine! Fuck (Vladimir) Putin! Stop the War! - Send A Stop The War Message To The World With Your Profile Picture\n\n\nLet's try the ukraine flag in the background (with the built-in `Ukraine` helper method):\n\n\n``` go\npunks.Tile( 0 ).Ukraine().Zoom( 4 ).Save( \"./morepunk0_flag(ukraine)@4x.png\" )\npunks.Tile( 18 ).Ukraine().Zoom( 4 ).Save( \"./morepunk18_flag(ukraine)@4x.png\" )\npunks.Tile( 40 ).Ukraine().Zoom( 4 ).Save( \"./morepunk40_flag(ukraine)@4x.png\" )\npunks.Tile( 88 ).Ukraine().Zoom( 4 ).Save( \"./morepunk88_flag(ukraine)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/morepunk0_flag(ukraine)@4x.png)\n![](i/morepunk18_flag(ukraine)@4x.png)\n![](i/morepunk40_flag(ukraine)@4x.png)\n![](i/morepunk88_flag(ukraine)@4x.png)\n\n\nOr try two-colored with the background in blue\nand the silhouette (foreground) in yellow and vice versa:\n\n``` go\npunks.Tile( 0 ).Silhouette(\"#ffdd00\").Background(\"#0057b7\").Zoom( 4 ).Save( \"./morepunk0_silhouette(ukraine)@4x.png\" )\npunks.Tile( 18 ).Silhouette(\"#0057b7\").Background(\"#ffdd00\").Zoom( 4 ).Save( \"./morepunk18_silhouette(ukraine)@4x.png\" )\npunks.Tile( 40 ).Silhouette(\"#ffdd00\").Background(\"#0057b7\").Zoom( 4 ).Save( \"./morepunk40_silhouette(ukraine)@4x.png\" )\npunks.Tile( 88 ).Silhouette(\"#0057b7\").Background(\"#ffdd00\").Zoom( 4 ).Save( \"./morepunk88_silhouette(ukraine)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/morepunk0_silhouette(ukraine)@4x.png)\n![](i/morepunk18_silhouette(ukraine)@4x.png)\n![](i/morepunk40_silhouette(ukraine)@4x.png)\n![](i/morepunk88_silhouette(ukraine)@4x.png)\n\n\n\n\n\n## Are Gophers, The New Punks?\n\nLet's retry with [**Egon Elbre's gophers collection**](https://github.com/egonelbre/gophers)\nin the 32x32 pixel format.\nSee the all-in-one composite image with 35 gophers in a 7x5 grid -\n[`gophers.png`](gophers.png)\n\n![](gophers.png)  (~14kb)\n\n\n\nLet's create a program to mint gopher pixel art images.\n\n### Step 1 -  Read gopher composite image\n\n\n``` go\npackage main\n\n\nimport (\n  \"fmt\"\n  \"github.com/learnpixelart/pixelart.go/pixelart\"\n)\n\n\nfunc main() {\n\n  fmt.Printf( \"Hello, Pixel Art v%s!\\n\", pixelart.Version )\n\n  path     := \"./gophers.png\"\n  tileSize := pixelart.Point{32, 32}\n  punks    := pixelart.ReadImageComposite( path, \u0026tileSize )\n\n  fmt.Println( gophers.Bounds() )\n  //=\u003e (0,0)-(224,160)\n}\n```\n\n\n### Step 2 - Start minting\n\nLet's mint gopher #0 (neutral), #1 (pirate), #16 (heart eyes), and #28 (mind blown).\nAdd inside `func main()`:\n\n\n``` go\ngopher := gophers.Tile( 0 )\nfmt.Println( gopher.Bounds() )\n//=\u003e (0,0)-(32,32)\n\ngopher.Save( \"./gopher0.png\" )\n\ngophers.Tile( 1 ).Save( \"./gopher1.png\" )\ngophers.Tile( 16 ).Save( \"./gopher16.png\" )\ngophers.Tile( 28 ).Save( \"./gopher28.png\" )\n\n```\n\nAnd voila!\n\n![](i/gopher0.png)\n![](i/gopher1.png)\n![](i/gopher16.png)\n![](i/gopher28.png)\n\n\nLet's change the zoom factor:\n\n``` go\ngophers.Tile( 0 ).Zoom( 4 ).Save( \"./gopher0@4x.png\" )\ngophers.Tile( 1 ).Zoom( 4 ).Save( \"./gopher1@4x.png\" )\ngophers.Tile( 16 ).Zoom( 4 ).Save( \"./gopher16@4x.png\" )\ngophers.Tile( 28 ).Zoom( 4 ).Save( \"./gopher28@4x.png\" )\n```\n\nAnd voila in 4x!\n\n![](i/gopher0@4x.png)\n![](i/gopher1@4x.png)\n![](i/gopher16@4x.png)\n![](i/gopher28@4x.png)\n\n\n\nProof-of the pudding.\nIf you want to run the ready-made sample\nprogram in [**`01_tile_(gophers)/`**](01_tile_(gophers)) yourself try:\n\n- Generate a go module (`go.mod`)\n- Add the pixelart package via go get to `go.mod`\n- Run the code\n\n```\n$ cd 01_tile_(gophers)\n$ go mod init example.com/01_tile\n$ go get github.com/learnpixelart/pixelart.go/pixelart\n$ go run main.go\n```\n\n\nLet's try with the classic gray-ish\nbackground in red/green/blue (rgb) as a hexstring `#638596`:\n\n\n``` go\ngophers.Tile( 0 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./gopher0_(grayish)@4x.png\" )\ngophers.Tile( 1 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./gopher1_(grayish)@4x.png\" )\ngophers.Tile( 16 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./gopher16_(grayish)@4x.png\" )\ngophers.Tile( 28 ).Background( \"#638596\" ).Zoom( 4 ).Save( \"./gopher28_(grayish)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/gopher0_(grayish)@4x.png)\n![](i/gopher1_(grayish)@4x.png)\n![](i/gopher16_(grayish)@4x.png)\n![](i/gopher28_(grayish)@4x.png)\n\n\n### Bonus - Glory to Ukraine! Fuck (Vladimir) Putin! Stop the War! - Send A Stop The War Message To The World With Your Profile Picture\n\n\nLet's try the ukraine flag in the background (with the built-in `Ukraine` helper method):\n\n\n``` go\ngophers.Tile( 0 ).Ukraine().Zoom( 4 ).Save( \"./gopher0_flag(ukraine)@4x.png\" )\ngophers.Tile( 1 ).Ukraine().Zoom( 4 ).Save( \"./gopher1_flag(ukraine)@4x.png\" )\ngophers.Tile( 16 ).Ukraine().Zoom( 4 ).Save( \"./gopher16_flag(ukraine)@4x.png\" )\ngophers.Tile( 28 ).Ukraine().Zoom( 4 ).Save( \"./gopher28_flag(ukraine)@4x.png\" )\n```\n\nAnd voila!\n\n![](i/gopher0_flag(ukraine)@4x.png)\n![](i/gopher1_flag(ukraine)@4x.png)\n![](i/gopher16_flag(ukraine)@4x.png)\n![](i/gopher28_flag(ukraine)@4x.png)\n\n\n\n# 2\n\n## 10 000 Punks - The Free Do-It-Yourself (DIY) White Label Quick Starter Edition\n\n\u003e Q: Dear sir, how do I get rich in ~bits-coin~ punks?\n\u003e\n\u003e A: If we all buy ~bits-coin~ punks from one another\n\u003e at ever higher prices we'll all be rich beyond our wildest dreams.\n\u003e\n\u003e 21 million bits-coin. 10 000 punks. Do the math.\n\n\nLet's (re)create from zero / scratch a pixel-perfect\ncopy of the Matt \u0026 John's® 10 000 punks collection (Anno 2017).\n\nYes, you can. Do-it-yourself (DIY) and\nown 100% forever your home-made free clean-room copy\nof the billion dollar (2400×2400) bitmap\nthat kicked-off\na trillion dollar get-rich-quick digital art\nmania / bubble in 2021 -\nselling \"decentralized\" ~blockchain tokens~\ndatabase records\nto ever greater fools at ever higher prices.\n\n\n###  Inside the Magic Money Machine - Mint 10 000 Unique Punks from 11 Archtetypes 'n' 122 Attributes\n\nLet's copy and (re)use all punk (building) blocks\nin the basic series (24×24):\n\n11 Archetypes:\n\nMale 1/2/3/4 ![](basic/male1.png)\n![](basic/male2.png)\n![](basic/male3.png)\n![](basic/male4.png),\nFemale 1/2/3/4 ![](basic/female1.png)\n![](basic/female2.png)\n![](basic/female3.png)\n![](basic/female4.png),\nZombie ![](basic/zombie.png),\nApe ![](basic/ape.png),\nAlien ![](basic/alien.png)\n\n\u003c!-- note:\n  sort attributes a-z for now - why? why not?\n--\u003e\n\n122 Attributes (by category and a-z):\n- Hat -\n  Bandana (m/f)\n  ![](basic/m/bandana.png)\n  ![](basic/f/bandana.png),\n  Beanie (m)\n  ![](basic/m/beanie.png),\n  Cap (m/f)\n  ![](basic/m/cap.png)\n  ![](basic/f/cap.png),\n  Cap Forward (m)\n  ![](basic/m/capforward.png),\n  Cowboy Hat (m)\n  ![](basic/m/cowboyhat.png),\n  Do-rag (m)\n  ![](basic/m/dorag.png),\n  Fedora (m)\n  ![](basic/m/fedora.png),\n  Headband (m/f)\n  ![](basic/m/headband.png)\n  ![](basic/f/headband.png),\n  Hoodie (m)\n  ![](basic/m/hoodie.png),\n  Knitted Cap (m/f)\n  ![](basic/m/knittedcap.png)\n  ![](basic/f/knittedcap.png),\n  Pilot Helmet (f)\n  ![](basic/f/pilothelmet.png),\n  Police Cap (m)\n  ![](basic/m/policecap.png),\n  Tassle Hat (f)\n  ![](basic/f/tasslehat.png),\n  Tiara (f)\n  ![](basic/f/tiara.png),\n  Top Hat (m)\n  ![](basic/m/tophat.png)\n- Hair -\n  Blonde Bob (f)\n  ![](basic/f/blondebob.png),\n  Blonde Short (f)\n  ![](basic/f/blondeshort.png),\n  Clown Hair Green (m/f)\n  ![](basic/m/clownhairgreen.png)\n  ![](basic/f/clownhairgreen.png),\n  Crazy Hair (m/f)\n  ![](basic/m/crazyhair.png)\n  ![](basic/f/crazyhair.png),\n  Dark Hair (f)\n  ![](basic/f/darkhair.png),\n  Frumpy Hair (m/f)\n  ![](basic/m/frumpyhair.png)\n  ![](basic/f/frumpyhair.png),\n  Half Shaved (f)\n  ![](basic/f/halfshaved.png),\n  Messy Hair (m/f)\n  ![](basic/m/messyhair.png)\n  ![](basic/f/messyhair.png),\n  Mohawk (m/f)\n  ![](basic/m/mohawk.png)\n  ![](basic/f/mohawk.png),\n  Mohawk Dark (m/f)\n  ![](basic/m/mohawkdark.png)\n  ![](basic/f/mohawkdark.png),\n  Mohawk Thin (m/f)\n  ![](basic/m/mohawkthin.png)\n  ![](basic/f/mohawkthin.png),\n  Orange Side (f)\n  ![](basic/f/orangeside.png),\n  Peak Spike (m)\n  ![](basic/m/peakspike.png),\n  Pigtails (f)\n  ![](basic/f/pigtails.png),\n  Pink With Hat (f)\n  ![](basic/f/pinkwithhat.png),\n  Purple Hair (m)\n  ![](basic/m/purplehair.png),\n  Red Mohawk (f)\n  ![](basic/f/redmohawk.png),\n  Shaved Head (m)\n  ![](basic/m/shavedhead.png),\n  Straight Hair (f)\n  ![](basic/f/straighthair.png),\n  Straight Hair Blonde (f)\n  ![](basic/f/straighthairblonde.png),\n  Straight Hair Dark (f)\n  ![](basic/f/straighthairdark.png),\n  Stringy Hair (m/f)\n  ![](basic/m/stringyhair.png)\n  ![](basic/f/stringyhair.png),\n  Vampire Hair (m)\n  ![](basic/m/vampirehair.png),\n  Wild Blonde (f)\n  ![](basic/f/wildblonde.png),\n  Wild Hair (m/f)\n  ![](basic/m/wildhair.png)\n  ![](basic/f/wildhair.png),\n  Wild White Hair (f)\n  ![](basic/f/wildwhitehair.png)\n- Eyes -\n  3D Glasses (m/f)\n   ![](basic/m/3dglasses.png)\n   ![](basic/f/3dglasses.png),\n  Big Shades (m/f)\n  ![](basic/m/bigshades.png)\n  ![](basic/f/bigshades.png),\n  Classic Shades (m/f)\n  ![](basic/m/classicshades.png)\n  ![](basic/f/classicshades.png),\n  Eye Mask (m/f)\n  ![](basic/m/eyemask.png)\n  ![](basic/f/eyemask.png),\n  Eye Patch (m/f)\n  ![](basic/m/eyepatch.png)\n  ![](basic/f/eyepatch.png),\n  Horned Rim Glasses (m/f)\n  ![](basic/m/hornedrimglasses.png)\n  ![](basic/f/hornedrimglasses.png),\n  Nerd Glasses (m/f)\n  ![](basic/m/nerdglasses.png)\n  ![](basic/f/nerdglasses.png),\n  Regular Shades (m/f)\n  ![](basic/m/regularshades.png)\n  ![](basic/f/regularshades.png),\n  Small Shades (m)\n  ![](basic/m/smallshades.png),\n  VR (m/f)\n  ![](basic/m/vr.png)\n  ![](basic/f/vr.png),\n  Welding Goggles (f)\n  ![](basic/f/weldinggoggles.png)\n- Eyes (Makeup) -\n  Blue Eye Shadow (f)\n  ![](basic/f/blueeyeshadow.png),\n  Clown Eyes Blue (m/f)\n  ![](basic/m/clowneyesblue.png)\n  ![](basic/f/clowneyesblue.png),\n  Clown Eyes Green (m/f)\n  ![](basic/m/clowneyesgreen.png)\n  ![](basic/f/clowneyesgreen.png),\n  Green Eye Shadow (f)\n  ![](basic/f/greeneyeshadow.png),\n  Purple Eye Shadow (f)\n  ![](basic/f/purpleeyeshadow.png)\n- Blemishes -\n  Mole (m/f)\n   ![](basic/m/mole.png)\n   ![](basic/f/mole.png),\n  Rosy Cheeks (m/f)\n   ![](basic/m/rosycheeks.png)\n   ![](basic/f/rosycheeks.png),\n  Spots (m/f)\n   ![](basic/m/spots.png)\n   ![](basic/f/spots.png)\n- Nose -\n  Clown Nose (m/f)\n   ![](basic/m/clownnose.png)\n   ![](basic/f/clownnose.png),\n- Ears -\n  Earring (m/f)\n   ![](basic/m/earring.png)\n   ![](basic/f/earring.png)\n- Mouth -\n  Buck Teeth (m)\n   ![](basic/m/buckteeth.png),\n  Frown (m)\n   ![](basic/m/frown.png),\n  Smile (m)\n   ![](basic/m/smile.png)\n- Mouth (Makeup) -\n  Black Lipstick (f)\n   ![](basic/f/blacklipstick.png),\n  Hot Lipstick (f)\n   ![](basic/f/hotlipstick.png),\n  Purple Lipstick (f)\n   ![](basic/f/purplelipstick.png)\n- Mouth Prop -\n  Cigarette (m/f)\n   ![](basic/m/cigarette.png)\n   ![](basic/f/cigarette.png),\n  Medical Mask (m/f)\n   ![](basic/m/medicalmask.png)\n   ![](basic/f/medicalmask.png),\n  Pipe (m/f)\n   ![](basic/m/pipe.png)\n   ![](basic/f/pipe.png),\n  Vape (m/f)\n   ![](basic/m/vape.png)\n   ![](basic/f/vape.png)\n- Beard -\n  Big Beard (m)\n   ![](basic/m/bigbeard.png),\n  Chinstrap (m)\n   ![](basic/m/chinstrap.png),\n  Front Beard (m)\n   ![](basic/m/frontbeard.png),\n  Front Beard Dark (m)\n   ![](basic/m/frontbearddark.png),\n  Goat (m)\n   ![](basic/m/goat.png),\n  Handlebars (m)\n   ![](basic/m/handlebars.png),\n  Luxurious Beard (m)\n   ![](basic/m/luxuriousbeard.png),\n  Mustache (m)\n   ![](basic/m/mustache.png),\n  Muttonchops (m)\n   ![](basic/m/muttonchops.png),\n  Normal Beard (m)\n   ![](basic/m/normalbeard.png),\n  Normal Beard Black (m)\n   ![](basic/m/normalbeardblack.png),\n  Shadow Beard (m)\n   ![](basic/m/shadowbeard.png)\n- Neck Accessory -\n  Choker (f)\n   ![](basic/f/choker.png),\n  Gold Chain (m/f)\n   ![](basic/m/goldchain.png)\n   ![](basic/f/goldchain.png),\n  Silver Chain (m/f)\n   ![](basic/m/silverchain.png)\n   ![](basic/f/silverchain.png)\n\n\n\u003c!-- break --\u003e\n\n(Source: [Punk (Building) Blocks - Basic Series (24×24)](https://github.com/cryptopunksnotdead/punks.blocks#basic-punk-series-2424))\n\n\n\nLet's wipe up a `generatePunk`\nfunction that\npastes / composes together\nthe building blocks / attributes and returns\na ready-to-save image. Example:\n\n\n``` go\n// generate punk #0\npunk = generatePunk( \"Female 2\", \"Earring\", \"Blonde Bob\", \"Green Eye Shadow\" )\npunk.Save( \"./punk0.png\" )\npunk.Zoom(20).Save( \"./punk0@20x.png\" )\n\n// generate punk #1\npunk = generatePunk( \"Male 1\", \"Smile\", \"Mohawk\" )\npunk.Save( \"./punk1.png\" )\npunk.Zoom(20).Save( \"./punk1@20x.png\" )\n```\n\n\nHere we go - the billion dollar formula:\n\n``` go\npackage main\n\n\nimport (\n  \"fmt\"\n  \"strings\"\n  \"regexp\"\n\n  \"github.com/learnpixelart/pixelart.go/pixelart\"\n)\n\n// allow (ignore):\n//    space ( ),\n//    underscore (_),\n//    dash (-)\nvar normalizeRegexp = regexp.MustCompile( \"[ _-]\" )\n\nfunc normalize( str string ) string {\n    str = strings.ToLower( str )\n    str = normalizeRegexp.ReplaceAllString( str, \"\" )\n    return str\n}\n\n\n\nvar dir = \"../basic\"\n\nfunc generatePunk( values ...string ) *pixelart.Image {\n  punkType       := values[0]\n  attributeNames := values[1:len(values)]\n\n  punkType = normalize( punkType )\n\n  path   :=  dir + \"/\" + punkType + \".png\"\n  punk := pixelart.ReadImage( path )\n\n  var m_or_f string\n  if strings.Index( punkType, \"female\" ) != -1 {\n    m_or_f = \"f\"\n  } else {\n    m_or_f = \"m\"\n  }\n\n\n  for _, attributeName := range attributeNames {\n    if attributeName == \"\" {   // skip empty attributes\n      continue\n    }\n\n    attributeName = normalize( attributeName )\n    path       = dir + \"/\" + m_or_f + \"/\" + attributeName + \".png\"\n    attribute   := pixelart.ReadImage( path )\n\n    punk.Paste( attribute )\n  }\n\n  return punk\n}\n```\n\n\nLet's test drive punk #0 and punk 1\n\n``` go\nfunc main() {\n  fmt.Printf( \"Hello, Pixel Art v%s!\\n\", pixelart.Version )\n\n  // test drive\n  // generate punk #0\n  punk := generatePunk( \"Female 2\", \"Earring\", \"Blonde Bob\", \"Green Eye Shadow\" )\n  punk.Save( \"punk0.png\" )\n  punk.Zoom(20).Save( \"punk0@20x.png\" )\n\n  // generate punk #1\n  punk = generatePunk( \"Male 1\", \"Smile\", \"Mohawk\" )\n  punk.Save( \"punk1.png\" )\n  punk.Zoom(20).Save( \"punk1@20x.png\" )\n}\n```\n\nand voila! In the original 24×24 format:\n\n\n\n![](i/punk0.png)\n![](i/punk1.png)\n\n\nAnd 20x (480×480):\n\n![](i/punk0@20x.png)\n![](i/punk1@20x.png)\n\n\n\nNote: If you use your own building blocks\nmake sure your type and attribute names\nmatch the filenames (without the `.png` extension).\nFor the matching algorithm all names\nget automatically downcased and all spaces deleted,\nthus,\n`Male 1` will map to `male1.png` ![](basic/male1.png)\nand `3D Glasses` to `3dglasses.png` ![](basic/m/3dglasses.png)\nand `Knitted Cap` to `knittedcap.png` ![](basic/m/knittedcap.png)\nand so on.\n\n\n\n\n\n\nLet's read-in all meta data records for all 10 000 punks.\nSee the [punks.csv](punks.csv) dataset that reads:\n\n```\ntype, attribute1, attribute2, attribute3, attribute4, attribute5, attribute6, attribute7\nFemale 2, Earring, Blonde Bob, Green Eye Shadow,,,,\nMale 1, Smile, Mohawk,,,,,\nFemale 3, Wild Hair,,,,,,\nMale 1, Wild Hair, Pipe, Nerd Glasses,,,,\nMale 2, Goat, Earring, Wild Hair, Big Shades,,,\nFemale 2, Earring, Half Shaved, Purple Eye Shadow,,,,\nMale 2, Do-rag,,,,,,\nFemale 2, Spots, Wild White Hair, Clown Eyes Blue,,,,\nMale 1, Luxurious Beard, Messy Hair,,,,,\nMale 2, Big Beard, Police Cap, Clown Nose,,,,\nFemale 1, Mohawk, Blue Eye Shadow,,,,,\nFemale 2, Black Lipstick, Straight Hair Dark, Clown Eyes Green,,,,\n...\n```\n\n\nLet's try:\n\n``` go\nrecs := readCSV( \"../punks.csv\" )\nfmt.Printf( \"%d punk(s)\\n\", len( recs ) )\n//=\u003e 10 000 punk(s)\n```\n\n\nAnd to wrap up let's loop over all 10 000 punks\nand generate a 24×24 version and a 20x zoom, that is,\n480×480. Let's go:\n\n\n``` go\nfor i,rec := range recs {\n    fmt.Printf( \"==\u003e %d - %v\\n\", i, rec )\n    punk = generatePunk( rec... )\n\n    name := fmt.Sprintf(\"punk%d\", i )\n\n    punk.Save( \"./o/\" + name + \".png\" )\n    punk.Zoom(20).Save( \"./o/\" + name + \"@20x.png\" )\n}\n```\n\nYes, that's it.\nIn the `/o` directory you will now find\ntwo images per punk - in the orginal format, that is, 24×24\nand 20x, that is, 480×480 - and get:\n\n```\no/\n  punk0.png\n  punk0@20x.png\n  punk1.png\n  punk1@20x.png\n  punk2.png\n  punk2@20x.png\n  punk3.png\n  punk3@20x.png\n  punk4.png\n  punk4@20x.png\n  punk5.png\n  punk5@20x.png\n  punk6.png\n  punk6@20x.png\n  punk7.png\n  punk7@20x.png\n  punk8.png\n  punk8@20x.png\n  ...\n```\n\nLet's open up the first hundred punks, that is, `punk0.png` to `punk99.png`:\n\n![](i/punk0.png)\n![](i/punk1.png)\n![](i/punk2.png)\n![](i/punk3.png)\n![](i/punk4.png)\n![](i/punk5.png)\n![](i/punk6.png)\n![](i/punk7.png)\n![](i/punk8.png)\n![](i/punk9.png)\n![](i/punk10.png)\n![](i/punk11.png)\n![](i/punk12.png)\n![](i/punk13.png)\n![](i/punk14.png)\n![](i/punk15.png)\n![](i/punk16.png)\n![](i/punk17.png)\n![](i/punk18.png)\n![](i/punk19.png)\n![](i/punk20.png)\n![](i/punk21.png)\n![](i/punk22.png)\n![](i/punk23.png)\n![](i/punk24.png)\n![](i/punk25.png)\n![](i/punk26.png)\n![](i/punk27.png)\n![](i/punk28.png)\n![](i/punk29.png)\n![](i/punk30.png)\n![](i/punk31.png)\n![](i/punk32.png)\n![](i/punk33.png)\n![](i/punk34.png)\n![](i/punk35.png)\n![](i/punk36.png)\n![](i/punk37.png)\n![](i/punk38.png)\n![](i/punk39.png)\n![](i/punk40.png)\n![](i/punk41.png)\n![](i/punk42.png)\n![](i/punk43.png)\n![](i/punk44.png)\n![](i/punk45.png)\n![](i/punk46.png)\n![](i/punk47.png)\n![](i/punk48.png)\n![](i/punk49.png)\n![](i/punk50.png)\n![](i/punk51.png)\n![](i/punk52.png)\n![](i/punk53.png)\n![](i/punk54.png)\n![](i/punk55.png)\n![](i/punk56.png)\n![](i/punk57.png)\n![](i/punk58.png)\n![](i/punk59.png)\n![](i/punk60.png)\n![](i/punk61.png)\n![](i/punk62.png)\n![](i/punk63.png)\n![](i/punk64.png)\n![](i/punk65.png)\n![](i/punk66.png)\n![](i/punk67.png)\n![](i/punk68.png)\n![](i/punk69.png)\n![](i/punk70.png)\n![](i/punk71.png)\n![](i/punk72.png)\n![](i/punk73.png)\n![](i/punk74.png)\n![](i/punk75.png)\n![](i/punk76.png)\n![](i/punk77.png)\n![](i/punk78.png)\n![](i/punk79.png)\n![](i/punk80.png)\n![](i/punk81.png)\n![](i/punk82.png)\n![](i/punk83.png)\n![](i/punk84.png)\n![](i/punk85.png)\n![](i/punk86.png)\n![](i/punk87.png)\n![](i/punk88.png)\n![](i/punk89.png)\n![](i/punk90.png)\n![](i/punk91.png)\n![](i/punk92.png)\n![](i/punk93.png)\n![](i/punk94.png)\n![](i/punk95.png)\n![](i/punk96.png)\n![](i/punk97.png)\n![](i/punk98.png)\n![](i/punk99.png)\n\n\nAnd let's have a looksie at the biggie 20x (480×480) versions:\n\n\n![](i/punk0@20x.png)\n![](i/punk1@20x.png)\n\nand so on.\n\n\n\n\n### Bonus -  Generate an All-In-One (2400×2400) Composite Image\n\nLet's generate an all-in-one composite image holding the complete\ncollection of 10 000 punks in a 100×100 grid.\n\n``` go\npunks := pixelart.NewImageComposite( 100, 100,\n                                    \u0026pixelart.Point{24, 24})\n\nfor i,rec := range recs {\n    fmt.Printf( \"==\u003e %d - %v\\n\", i, rec )\n    punk = generatePunk( rec... )\n    punks.Add( punk )\n}\n\npunks.Save( \"./o/punks.png\" )\n```\n\nYes, that's it.\nOpen up `punks.png` to have a looksie.\n\n![](i/punks-preview.png)\n\n\nNote: Only showing the first one hundred punks as a preview.\nDownload [**punks.png**](i/punks.png) ~1MB for the full monty.\n\n\n\n\n\n\n\n\nTo be continued...\n\n\n\n\n## Questions? Comments?\n\nYes, you can. Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.\n\n\n## License\n\n![](https://publicdomainworks.github.io/buttons/zero88x31.png)\n\nThe Programming Punk Step-by-Step book / guide\nis dedicated to the public domain.\nUse it as you please with no restrictions whatsoever.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryptopunksnotdead%2Flets-go-programming-cryptopunks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcryptopunksnotdead%2Flets-go-programming-cryptopunks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryptopunksnotdead%2Flets-go-programming-cryptopunks/lists"}