Skip to content

Commit 80d960c

Browse files
🎉 initial commit
0 parents  commit 80d960c

16 files changed

+1414
-0
lines changed

.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
assets
2+
.dfx
3+
.DS_Store
4+
mint
5+
mint.zip
6+
identity.pem
7+
__pycache__
8+
punks.csv
9+
punks.json
10+
triple_distribution.png
11+
.venv
12+
assets.zip
13+
.pytest_cache
14+
temp

README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Instructions 🛠
2+
3+
## preparation 🍱
4+
5+
- create folder in root of project called `assets`
6+
- add your assets to the `assets` folder
7+
- cd into `generator`
8+
- run `poetry install`
9+
- adapt the `generator.py`, `oracle.py` and `utils.py` files to your needs
10+
- change `generator = 'ethflower_generator.generator:stop_mint'` to `generator = 'ethflower_generator.generator:assemble_svgs'`
11+
- make sure you use the right constants at the top of `generator.py`
12+
- run `poetry run generator`
13+
- profit? 💫
14+
15+
## helpers 💪
16+
17+
### decrease size of pngs in batch
18+
19+
```bash
20+
for name in *.png
21+
do
22+
sips -Z 200 "$name" -o "_thumbnail_${name}"
23+
done
24+
```
25+
26+
### rename in batch
27+
28+
```bash
29+
for name in *  ✔
30+
do
31+
mv "$name" "_thumbnail_${name}"
32+
done
33+
```
34+
35+
### remove prefix in batch
36+
37+
```bash
38+
for file in *;do
39+
mv $file ${file#BG_}
40+
done
41+
```
42+
43+
### swap prefix and suffix in batch
44+
45+
```bash
46+
for file in WHITE_*;do  ✔
47+
name=${file#WHITE_}
48+
echo mv $file ${name%.png}_WHITE.png
49+
done
50+
```
51+
52+
## uploading 💾
53+
54+
- you cant upload the entire collection at once, split it in half and upload each half

canister_ids.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"punks_assets": {
3+
"ic": "zt63f-rqaaa-aaaae-qadaq-cai"
4+
}
5+
}

dfx.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"canisters": {
3+
"punks_assets": {
4+
"source": ["assets"],
5+
"type": "assets"
6+
}
7+
},
8+
"networks": {
9+
"local": {
10+
"bind": "127.0.0.1:8000",
11+
"type": "ephemeral"
12+
}
13+
},
14+
"version": 1
15+
}

generator/.python-version

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.8.6

generator/generator/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = '0.1.0'

generator/generator/generator.py

+264
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
from bs4 import BeautifulSoup
2+
from pathlib import Path
3+
from generator.utils import pick_choice
4+
from generator.utils import calculate_weights, check_for_triples, get_filenames, add_assets, add_petal_animation, get_trait, print_progress_bar
5+
from generator.oracle import add_oracle
6+
from generator.plot import plot_bar
7+
import generator.weights as weights
8+
import json
9+
import csv
10+
11+
12+
ASSET_CANISTER_URL = "https://zt63f-rqaaa-aaaae-qadaq-cai.raw.ic0.app/"
13+
# ASSET_CANISTER_URL = "./"
14+
COLLECTION_NAME = "punks"
15+
COLLECTION_SIZE = 7761 # + 16 uniques = 7777
16+
17+
18+
def assemble_svgs():
19+
"""assemble the svgs for the collection"""
20+
21+
# get all the relative filenames for the different layers.
22+
# specify substrings in exclude_list to exclude certain files by substrings
23+
backgrounds = get_filenames("../assets/BACKGROUNDS",
24+
exclude_list=["thumbnail", ".DS_Store"])
25+
background_accessories = get_filenames(
26+
"../assets/BACKGROUND_ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"])
27+
28+
body_heads = get_filenames(
29+
"../assets/BODY_HEAD", exclude_list=["thumbnail", ".DS_Store"])
30+
31+
top_head_leafs = get_filenames(
32+
"../assets/BODY_HEAD_BASIC/TOP_HEAD_LEAFS", exclude_list=["thumbnail", ".DS_Store"])
33+
34+
top_head_crowns = get_filenames(
35+
"../assets/BODY_HEAD_BASIC/TOP_HEAD_CROWNS", exclude_list=["thumbnail", ".DS_Store"])
36+
37+
top_head_chains = get_filenames(
38+
"../assets/BODY_HEAD_BASIC/TOP_HEAD_CHAINS", exclude_list=["thumbnail", ".DS_Store"])
39+
40+
masks = get_filenames(
41+
"../assets/MASKS", exclude_list=["thumbnail", ".DS_Store"])
42+
43+
eyes = get_filenames(
44+
"../assets/MID_HEAD/EYES", exclude_list=["thumbnail", ".DS_Store"])
45+
46+
accessories = get_filenames(
47+
"../assets/MID_HEAD/ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"])
48+
49+
bottom_head_accessories = get_filenames(
50+
"../assets/MID_HEAD/BOTTOM_HEAD_ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"])
51+
52+
body_accessories = get_filenames(
53+
"../assets/BODY_ACCESSORIES/BODY", exclude_list=["thumbnail", ".DS_Store"])
54+
55+
necks = get_filenames(
56+
"../assets/BODY_ACCESSORIES/NECK", exclude_list=["thumbnail", ".DS_Store"])
57+
58+
frames = get_filenames(
59+
"../assets/FRONT_FRAME", exclude_list=["thumbnail", ".DS_Store"])
60+
61+
lasers = get_filenames(
62+
"../assets/LASER_EYE", exclude_list=["thumbnail", ".DS_Store"])
63+
64+
uniques = get_filenames(
65+
"../assets/UNIQUES", exclude_list=["thumbnail", ".DS_Store"])
66+
67+
# get the path to the template svg file the assets will be embedded in
68+
template = Path(__file__).parent / "template.svg"
69+
70+
# open the template file and get the soup
71+
# this has to be done twice because we have call by reference
72+
with template.open() as svg_template:
73+
soup = BeautifulSoup(svg_template, 'xml')
74+
75+
with template.open() as svg_template:
76+
lowres_soup = BeautifulSoup(svg_template, 'xml')
77+
# the oracle code has to be added to the template only once
78+
# add_oracle(soup)
79+
# add_oracle(lowres_soup)
80+
81+
nfts = []
82+
83+
for i in range(COLLECTION_SIZE):
84+
85+
print_progress_bar(i, COLLECTION_SIZE, "Progress", "Complete")
86+
87+
background, lowres_background = pick_choice(
88+
backgrounds, weights.background)
89+
90+
background_accessory, lowres_background_accessory = pick_choice(
91+
background_accessories, weights.background_accessory)
92+
93+
body_head, lowres_body_head = pick_choice(
94+
body_heads, weights.body_head)
95+
96+
top_head_leaf, lowres_top_head_leaf = pick_choice(
97+
top_head_leafs, weights.top_head_leaf)
98+
top_head_crown, lowres_top_head_crown = pick_choice(
99+
top_head_crowns, weights.top_head_crown)
100+
top_head_chain, lowres_top_head_chain = pick_choice(
101+
top_head_chains, weights.top_head_chain)
102+
mask, lowres_mask = pick_choice(masks, weights.mask)
103+
104+
# those are only present when the punk doesnt wear a mask
105+
eye, lowres_eye = pick_choice(eyes, weights.eye)
106+
accessory, lowres_accessory = pick_choice(
107+
accessories, weights.accessory)
108+
bottom_head_accessory, lowres_bottom_head_accessory = pick_choice(
109+
bottom_head_accessories, weights.bottom_head_accessory)
110+
111+
body_accessory, lowres_body_accessory = pick_choice(
112+
body_accessories, weights.body_accessory)
113+
neck, lowres_neck = pick_choice(
114+
necks, weights.neck)
115+
frame, lowres_frame = pick_choice(
116+
frames, weights.frame)
117+
118+
laser, lowres_laser = pick_choice(
119+
lasers, weights.laser)
120+
121+
# check if mask is present and we use it instead
122+
if not 'NONE' in mask:
123+
eye, lowres_eye = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
124+
accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
125+
bottom_head_accessory, lowres_bottom_head_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
126+
127+
# check if bodyhead string contains btcflowerbrain
128+
if 'BTCFLOWERBRAIN' in body_head:
129+
top_head_leaf, lowres_top_head_leaf = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
130+
top_head_crown, lowres_top_head_crown = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
131+
top_head_chain, lowres_top_head_chain = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
132+
133+
# headphones dont work with btcflower brain
134+
if 'BTCFLOWERBRAIN' in body_head and 'HEADPHONES' in accessory:
135+
accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
136+
137+
# neck accessories dont work with hoodies or jackets
138+
if 'WINTER' in body_accessory or 'HOODIE' in body_accessory:
139+
neck, lowres_neck = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
140+
141+
# googles and glasses dont work with laser eyes and other accessories
142+
if 'GOGGLES' in eye or 'GLASSES' in eye:
143+
laser, lowres_laser = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
144+
accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png'
145+
146+
add_assets(
147+
soup,
148+
ASSET_CANISTER_URL,
149+
background=background,
150+
background_accessory=background_accessory,
151+
body_head=body_head,
152+
top_head_leaf=top_head_leaf,
153+
top_head_crown=top_head_crown,
154+
top_head_chain=top_head_chain,
155+
mask=mask,
156+
eye=eye,
157+
accessory=accessory,
158+
bottom_head_accessory=bottom_head_accessory,
159+
body_accessory=body_accessory,
160+
neck=neck,
161+
frame=frame,
162+
laser=laser,
163+
)
164+
165+
add_assets(
166+
lowres_soup,
167+
ASSET_CANISTER_URL,
168+
background=lowres_background,
169+
background_accessory=lowres_background_accessory,
170+
body_head=lowres_body_head,
171+
top_head_leaf=lowres_top_head_leaf,
172+
top_head_crown=lowres_top_head_crown,
173+
top_head_chain=lowres_top_head_chain,
174+
mask=lowres_mask,
175+
eye=lowres_eye,
176+
accessory=lowres_accessory,
177+
bottom_head_accessory=lowres_bottom_head_accessory,
178+
body_accessory=lowres_body_accessory,
179+
neck=lowres_neck,
180+
frame=lowres_frame,
181+
laser=lowres_laser,
182+
)
183+
184+
with Path("../assets/"+str(i+1)+".svg").open('w') as random_svg:
185+
random_svg.write(str(soup))
186+
with Path("../assets/"+str(i+1)+"_thumbnail.svg").open('w') as random_svg_low:
187+
random_svg_low.write(str(lowres_soup))
188+
189+
nfts.append(
190+
{
191+
"mint_number": i+1,
192+
"background": get_trait(background),
193+
"background_accessory": get_trait(background_accessory),
194+
"body_head": get_trait(body_head),
195+
"top_head_leaf": get_trait(top_head_leaf),
196+
"top_head_crown": get_trait(top_head_crown),
197+
"top_head_chain": get_trait(top_head_chain),
198+
"mask": get_trait(mask),
199+
"eye": get_trait(eye),
200+
"accessory": get_trait(accessory),
201+
"bottom_head_accessory": get_trait(bottom_head_accessory),
202+
"body_accessory": get_trait(body_accessory),
203+
"neck": get_trait(neck),
204+
"frame": get_trait(frame),
205+
"laser": get_trait(laser),
206+
'unique': 'NONE'
207+
}
208+
)
209+
210+
# build uniques
211+
for id, item in enumerate(uniques):
212+
unique, lowres_unique = pick_choice([item], [1])
213+
add_assets(
214+
soup,
215+
ASSET_CANISTER_URL,
216+
unique=unique,
217+
)
218+
219+
add_assets(
220+
lowres_soup,
221+
ASSET_CANISTER_URL,
222+
unique=lowres_unique,
223+
)
224+
225+
with Path("../assets/"+str(7761+id+1)+".svg").open('w') as random_svg:
226+
random_svg.write(str(soup))
227+
with Path("../assets/"+str(7761+id+1)+"_thumbnail.svg").open('w') as random_svg_low:
228+
random_svg_low.write(str(lowres_soup))
229+
230+
nfts.append(
231+
{
232+
"mint_number": 7761+id+1,
233+
"background": 'NONE',
234+
"background_accessory": 'NONE',
235+
"body_head": 'NONE',
236+
"top_head_leaf": 'NONE',
237+
"top_head_crown": 'NONE',
238+
"top_head_chain": 'NONE',
239+
"mask": 'NONE',
240+
"eye": 'NONE',
241+
"accessory": 'NONE',
242+
"bottom_head_accessory": 'NONE',
243+
"body_accessory": 'NONE',
244+
"neck": 'NONE',
245+
"frame": 'NONE',
246+
"laser": 'NONE',
247+
'unique': get_trait(unique, ".jpg"),
248+
}
249+
)
250+
251+
with open(f'{COLLECTION_NAME}.json', 'w') as f:
252+
json.dump(nfts, f, ensure_ascii=False, indent=4)
253+
254+
with open(f'{COLLECTION_NAME}.csv', 'w', newline='') as csvfile:
255+
spamwriter = csv.writer(csvfile)
256+
spamwriter.writerow(
257+
["mint_number", "background", "background_accessory", "body_head", "top_head_leaf", "top_head_crown", "top_head_chain", "mask", "eye", "accessory", "bottom_head_accessory", "body_accessory", "neck", "frame", "laser"])
258+
for entry in nfts:
259+
spamwriter.writerow(
260+
[entry["mint_number"], entry["background"], entry["background_accessory"], entry["body_head"], entry["top_head_leaf"], entry["top_head_crown"], entry["top_head_chain"], entry["mask"], entry["eye"], entry["accessory"], entry["bottom_head_accessory"], entry["body_accessory"], entry["neck"], entry["frame"], entry["laser"]])
261+
262+
263+
def stop_mint():
264+
print("you already minted")

0 commit comments

Comments
 (0)