synthpunks 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +10 -0
- data/README.md +28 -0
- data/Rakefile +39 -0
- data/config/spritesheet.json +1 -0
- data/config/spritesheet.png +0 -0
- data/lib/synthpunks/contract.rb +263 -0
- data/lib/synthpunks/image.rb +24 -0
- data/lib/synthpunks/version.rb +26 -0
- data/lib/synthpunks.rb +22 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a0c5233aa985d25b010831dca85d14e481489665af2e69f428959d4db3a56228
|
4
|
+
data.tar.gz: 6f1e5ee50bb527fcdc4baa1e82673885a1883d3dc06b982d3c9f018f58045899
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 90b18b54a84d472b62c0694389ca633b948f0ac45e5f63219f08e7ce63f0994542930e29ad86c6d1a97ae1483d10995c9603aa1fc7c8212d158c139fad5d823d
|
7
|
+
data.tar.gz: b0e77cb3d73d74a124628ea7da1af8f63c9ed5f5e595dbdffbf1a126e4bc29971236f3a7443006b081a2fbac7efeddbecbb2be49047a6abdf61f1706670f16fd
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Synth(etic) Punks - (Free Unlimited) 24×24 Pixel Punks For Everyone
|
2
|
+
|
3
|
+
|
4
|
+
synthpunks - (free unlimited) 24×24 pixel punks for everyone - yes, you can - generate / claim your own synth(etic) punks ("off-blockchain") for your own (ethereum) account 40-hexdigit addresses e.g. 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322; incl. 2x/4x/8x zoom for bigger sizes
|
5
|
+
|
6
|
+
|
7
|
+
* home :: [github.com/cryptopunksnotdead/cryptopunks](https://github.com/cryptopunksnotdead/cryptopunks)
|
8
|
+
* bugs :: [github.com/cryptopunksnotdead/cryptopunks/issues](https://github.com/cryptopunksnotdead/cryptopunks/issues)
|
9
|
+
* gem :: [rubygems.org/gems/synthpunks](https://rubygems.org/gems/synthpunks)
|
10
|
+
* rdoc :: [rubydoc.info/gems/synthpunks](http://rubydoc.info/gems/synthpunks)
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
...
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
## License
|
21
|
+
|
22
|
+
The scripts are dedicated to the public domain.
|
23
|
+
Use it as you please with no restrictions whatsoever.
|
24
|
+
|
25
|
+
|
26
|
+
## Questions? Comments?
|
27
|
+
|
28
|
+
Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/synthpunks/version.rb'
|
3
|
+
|
4
|
+
###
|
5
|
+
# hack/ quick fix for broken intuit_values - overwrite with dummy
|
6
|
+
class Hoe
|
7
|
+
def intuit_values( input ); end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
Hoe.spec 'synthpunks' do
|
13
|
+
|
14
|
+
self.version = Pixelart::Module::Synthpunks::VERSION
|
15
|
+
|
16
|
+
self.summary = 'synthpunks - (free unlimited) 24×24 pixel punks for everyone - yes, you can - generate / claim your own synth(etic) punks ("off-blockchain") for your own (ethereum) account 40-hexdigit addresses e.g. 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322; incl. 2x/4x/8x zoom for bigger sizes'
|
17
|
+
self.description = summary
|
18
|
+
|
19
|
+
self.urls = { home: 'https://github.com/cryptopunksnotdead/cryptopunks' }
|
20
|
+
|
21
|
+
self.author = 'Gerald Bauer'
|
22
|
+
self.email = 'wwwmake@googlegroups.com'
|
23
|
+
|
24
|
+
# switch extension to .markdown for gihub formatting
|
25
|
+
self.readme_file = 'README.md'
|
26
|
+
self.history_file = 'CHANGELOG.md'
|
27
|
+
|
28
|
+
self.extra_deps = [
|
29
|
+
['pixelart', '>= 1.3.6'],
|
30
|
+
['etherlite', '>= 0.3.1'],
|
31
|
+
]
|
32
|
+
|
33
|
+
self.licenses = ['Public Domain']
|
34
|
+
|
35
|
+
self.spec_extras = {
|
36
|
+
required_ruby_version: '>= 2.3'
|
37
|
+
}
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"attributes": [[0, "Human 1", "m", "l", "base"], [1, "Human 2", "m", "l", "base"], [2, "Human 3", "m", "l", "base"], [3, "Human 4", "m", "l", "base"], [4, "Zombie", "m", "l", "base"], [5, "Ape", "m", "l", "base"], [6, "Alien", "m", "l", "base"], [7, "Human Female 1", "f", "s", "base"], [8, "Human Female 2", "f", "s", "base"], [9, "Human Female 3", "f", "s", "base"], [10, "Human Female 4", "f", "s", "base"], [11, "Mole", "m", "l", "cheeks"], [12, "Rosy Cheeks", "m", "l", "cheeks"], [13, "Spots", "m", "l", "cheeks"], [14, "Clown Nose", "u", "l", "cheeks"], [15, "Mole", "f", "s", "cheeks"], [16, "Rosy Cheeks", "f", "s", "cheeks"], [17, "Spots", "f", "s", "cheeks"], [18, "Clown Nose", "f", "s", "cheeks"], [19, "Buck Teeth", "m", "l", "mouth"], [20, "Frown", "m", "l", "mouth"], [21, "Smile", "m", "l", "mouth"], [22, "Black Lipstick", "f", "u", "mouth"], [23, "Hot Lipstick", "f", "u", "mouth"], [24, "Purple Lipstick", "f", "u", "mouth"], [25, "Gold Chain", "m", "l", "neck"], [26, "Silver Chain", "m", "l", "neck"], [27, "Choker", "f", "u", "neck"], [28, "Gold Chain", "f", "u", "neck"], [29, "Silver Chain", "f", "u", "neck"], [30, "Big Beard", "m", "l", "beard"], [31, "Chinstrap", "m", "l", "beard"], [32, "Front Beard", "m", "l", "beard"], [33, "Front Beard Dark", "m", "l", "beard"], [34, "Goat", "m", "l", "beard"], [35, "Handlebars", "m", "l", "beard"], [36, "Luxurious Beard", "m", "l", "beard"], [37, "Mustache", "m", "l", "beard"], [38, "Muttonchops", "m", "l", "beard"], [39, "Normal Beard", "m", "l", "beard"], [40, "Normal Beard Black", "m", "l", "beard"], [41, "Shadow Beard", "m", "l", "beard"], [42, "Bandana", "m", "l", "headAccessory"], [43, "Beanie", "m", "l", "headAccessory"], [44, "Cap Forward", "u", "l", "headAccessory"], [45, "Cowboy Hat", "m", "l", "headAccessory"], [46, "Do-rag", "m", "l", "headAccessory"], [47, "Fedora", "m", "l", "headAccessory"], [48, "Headband", "u", "l", "headAccessory"], [49, "Hoodie", "m", "l", "headAccessory"], [50, "Knitted Cap", "u", "l", "headAccessory"], [51, "Police Cap", "m", "l", "headAccessory"], [52, "Top Hat", "m", "l", "headAccessory"], [53, "Cap", "u", "l", "headAccessory"], [54, "Crazy Hair", "m", "l", "headAccessory"], [55, "Frumpy Hair", "m", "l", "headAccessory"], [56, "Messy Hair", "u", "l", "headAccessory"], [57, "Mohawk", "u", "l", "headAccessory"], [58, "Mohawk Dark", "u", "l", "headAccessory"], [59, "Mohawk Thin", "u", "l", "headAccessory"], [60, "Peak Spike", "m", "l", "headAccessory"], [61, "Purple Hair", "m", "l", "headAccessory"], [62, "Shaved Head", "m", "l", "headAccessory"], [63, "Stringy Hair", "m", "l", "headAccessory"], [64, "Vampire Hair", "m", "l", "headAccessory"], [65, "Wild Hair", "m", "l", "headAccessory"], [66, "Clown Hair Green", "m", "l", "headAccessory"], [67, "Bandana", "f", "s", "headAccessory"], [68, "Beanie", "f", "s", "headAccessory"], [69, "Cap Forward", "f", "s", "headAccessory"], [70, "Cowboy Hat", "f", "s", "headAccessory"], [71, "Do-rag", "f", "s", "headAccessory"], [72, "Fedora", "f", "s", "headAccessory"], [73, "Headband", "f", "s", "headAccessory"], [74, "Hoodie", "f", "s", "headAccessory"], [75, "Knitted Cap", "f", "s", "headAccessory"], [76, "Pilot Helmet", "f", "s", "headAccessory"], [77, "Police Cap", "f", "s", "headAccessory"], [78, "Tassle Hat", "f", "s", "headAccessory"], [79, "Tiara", "f", "s", "headAccessory"], [80, "Top Hat", "f", "s", "headAccessory"], [81, "Cap", "f", "s", "headAccessory"], [82, "Blonde Short", "f", "s", "headAccessory"], [83, "Crazy Hair", "f", "s", "headAccessory"], [84, "Dark Hair", "f", "s", "headAccessory"], [85, "Frumpy Hair", "f", "s", "headAccessory"], [86, "Half Shaved", "f", "s", "headAccessory"], [87, "Messy Hair", "f", "s", "headAccessory"], [88, "Mohawk", "f", "s", "headAccessory"], [89, "Mohawk Dark", "f", "s", "headAccessory"], [90, "Mohawk Thin", "f", "s", "headAccessory"], [91, "Orange Side", "f", "s", "headAccessory"], [92, "Pigtails", "f", "s", "headAccessory"], [93, "Pink With Hat", "f", "s", "headAccessory"], [94, "Purple Hair", "f", "s", "headAccessory"], [95, "Red Mohawk", "f", "s", "headAccessory"], [96, "Shaved Head", "f", "s", "headAccessory"], [97, "Straight Hair", "f", "s", "headAccessory"], [98, "Straight Hair Blonde", "f", "s", "headAccessory"], [99, "Straight Hair Dark", "f", "s", "headAccessory"], [100, "Stringy Hair", "f", "s", "headAccessory"], [101, "Wild Blonde", "f", "s", "headAccessory"], [102, "Wild Hair", "f", "s", "headAccessory"], [103, "Wild White Hair", "f", "s", "headAccessory"], [104, "Blonde Bob", "f", "s", "headAccessory"], [105, "Clown Hair Green", "f", "s", "headAccessory"], [106, "Cigarette", "u", "l", "mouthAccessory"], [107, "Medical Mask", "u", "l", "mouthAccessory"], [108, "Pipe", "u", "l", "mouthAccessory"], [109, "Vape", "u", "l", "mouthAccessory"], [110, "Cigarette", "f", "s", "mouthAccessory"], [111, "Medical Mask", "f", "s", "mouthAccessory"], [112, "Pipe", "f", "s", "mouthAccessory"], [113, "Vape", "f", "s", "mouthAccessory"], [114, "Eyebrows", "u", "l", "eyes"], [115, "3D Glasses", "u", "l", "eyes"], [116, "Big Shades", "u", "l", "eyes"], [117, "Classic Shades", "u", "l", "eyes"], [118, "Eye Mask", "u", "l", "eyes"], [119, "Eye Patch", "u", "l", "eyes"], [120, "Horned Rim Glasses", "u", "l", "eyes"], [121, "Nerd Glasses", "u", "l", "eyes"], [122, "Regular Shades", "u", "l", "eyes"], [123, "Small Shades", "u", "l", "eyes"], [124, "VR", "u", "l", "eyes"], [125, "Clown Eyes Blue", "u", "l", "eyes"], [126, "Clown Eyes Green", "u", "l", "eyes"], [127, "3D Glasses", "f", "s", "eyes"], [128, "Big Shades", "f", "s", "eyes"], [129, "Classic Shades", "f", "s", "eyes"], [130, "Eye Mask", "f", "s", "eyes"], [131, "Eye Patch", "f", "s", "eyes"], [132, "Horned Rim Glasses", "f", "s", "eyes"], [133, "Nerd Glasses", "f", "s", "eyes"], [134, "Regular Shades", "f", "s", "eyes"], [135, "Small Shades", "f", "s", "eyes"], [136, "VR", "f", "s", "eyes"], [137, "Welding Goggles", "f", "s", "eyes"], [138, "Blue Eye Shadow", "f", "s", "eyes"], [139, "Green Eye Shadow", "f", "s", "eyes"], [140, "Clown Eyes Blue", "f", "s", "eyes"], [141, "Clown Eyes Green", "f", "s", "eyes"], [142, "Earring", "u", "l", "ears"], [143, "Earring", "f", "s", "ears"]], "ranges": {"base": [0, 7, 7, 11], "eyes": [114, 127, 127, 142], "cheeks": [11, 15, 15, 19], "ears": [142, 143, 143, 144], "mouth": [19, 22, 22, 25], "mouthAccessory": [106, 110, 110, 114], "neck": [25, 27, 27, 30], "beard": [30, 42, 42, 42], "headAccessory": [42, 67, 67, 106]}, "render_order": ["base", "cheeks", "mouth", "neck", "beard", "headAccessory", "mouthAccessory", "eyes", "ears"]}
|
Binary file
|
@@ -0,0 +1,263 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Synthpunks
|
4
|
+
|
5
|
+
SPRITESHEET = Pixelart::ImageComposite.read( "#{Pixelart::Module::Synthpunks.root}/config/spritesheet.png",
|
6
|
+
width: 24, height: 24 )
|
7
|
+
|
8
|
+
SPRITESHEET_ATTRIBUTES, SPRITESHEET_RANGES = begin
|
9
|
+
## build from spritesheet.json
|
10
|
+
config = read_json( "#{Pixelart::Module::Synthpunks.root}/config/spritesheet.json" )
|
11
|
+
|
12
|
+
attributes = []
|
13
|
+
config[ 'attributes' ].each do |rec|
|
14
|
+
attributes << rec[1] ## get attribute name
|
15
|
+
end
|
16
|
+
|
17
|
+
ranges = []
|
18
|
+
config[ 'render_order'].each do |key|
|
19
|
+
values = config[ 'ranges'][key]
|
20
|
+
## note: use exclusive (three dot...) ranges !!!
|
21
|
+
## e.g. 42...42 - range.size == 0 that is, MUST equal 0 !!!
|
22
|
+
ranges << [(values[0]...values[1]),
|
23
|
+
(values[2]...values[3])]
|
24
|
+
end
|
25
|
+
|
26
|
+
[attributes, ranges]
|
27
|
+
end
|
28
|
+
|
29
|
+
=begin
|
30
|
+
## note: use exclusive (three dot...) ranges !!!
|
31
|
+
SPRITESHEET_RANGES = [
|
32
|
+
[(0...7), (7...11)], ## base archetypes (male / female)
|
33
|
+
[(11...15), (15...19)],
|
34
|
+
[(19...22), (22...25)],
|
35
|
+
[(25...27), (27...30)],
|
36
|
+
[(30...42), (42...42)],
|
37
|
+
[(42...67), (67...106)],
|
38
|
+
[(106...110), (110...114)],
|
39
|
+
[(114...127), (127...142)],
|
40
|
+
[(142...143), (143...144)]
|
41
|
+
]
|
42
|
+
|
43
|
+
"ranges":
|
44
|
+
{"base": [0, 7, 7, 11],
|
45
|
+
"cheeks": [11, 15, 15, 19],
|
46
|
+
"mouth": [19, 22, 22, 25],
|
47
|
+
"neck": [25, 27, 27, 30],
|
48
|
+
"beard": [30, 42, 42, 42],
|
49
|
+
"headAccessory": [42, 67, 67, 106],
|
50
|
+
"mouthAccessory": [106, 110, 110, 114],
|
51
|
+
"eyes": [114, 127, 127, 142],
|
52
|
+
"ears": [142, 143, 143, 144]},
|
53
|
+
"render_order": ["base", "cheeks", "mouth",
|
54
|
+
"neck", "beard", "headAccessory",
|
55
|
+
"mouthAccessory", "eyes", "ears"]}
|
56
|
+
=end
|
57
|
+
|
58
|
+
|
59
|
+
# // Entropy 1,2-9
|
60
|
+
# function getAttributeCategories(uint256 id) public view returns (uint256[] memory) {
|
61
|
+
# uint256[4][9] memory spritesheetRanges = assets.spritesheetRanges();
|
62
|
+
# uint256 checks = 2 + randomUint(id, 1) % (spritesheetRanges.length - 3); // Number of bytes to check
|
63
|
+
# uint256[] memory attributes = new uint256[](checks);
|
64
|
+
# uint256 length = 0;
|
65
|
+
# for (uint256 i; i < checks; i++) {
|
66
|
+
# uint256 newAttribute = randomUint(id, 2+i) % (spritesheetRanges.length - 2) + 1; // Skip base category
|
67
|
+
#
|
68
|
+
# bool added = contains(attributes, newAttribute);
|
69
|
+
#
|
70
|
+
# if (added) {
|
71
|
+
# continue;
|
72
|
+
# }
|
73
|
+
#
|
74
|
+
# if (getGender(id) == Gender.Female) {
|
75
|
+
# if (!(spritesheetRanges[newAttribute][3] - spritesheetRanges[newAttribute][1] == 0)) {
|
76
|
+
# attributes[length] = newAttribute;
|
77
|
+
# length++;
|
78
|
+
# }
|
79
|
+
# } else {
|
80
|
+
# if (!(spritesheetRanges[newAttribute][2] - spritesheetRanges[newAttribute][0] == 0)) {
|
81
|
+
# attributes[length] = newAttribute;
|
82
|
+
# length++;
|
83
|
+
# }
|
84
|
+
# }
|
85
|
+
# }
|
86
|
+
#
|
87
|
+
# uint256[] memory attributesResized = new uint256[](length+1);
|
88
|
+
# attributesResized[0] = 0;
|
89
|
+
# for (uint256 i; i < length; i++) {
|
90
|
+
# attributesResized[i+1] = attributes[i];
|
91
|
+
# }
|
92
|
+
#
|
93
|
+
# return attributesResized;
|
94
|
+
# }
|
95
|
+
|
96
|
+
GENDER_MALE = 0
|
97
|
+
GENDER_FEMALE = 1
|
98
|
+
|
99
|
+
|
100
|
+
## Entropy 1,2-9
|
101
|
+
def self.getAttributeCategories( id )
|
102
|
+
## note: add 0 dummy for base upfront
|
103
|
+
attributes = [0]
|
104
|
+
|
105
|
+
gender = getGender(id) # note: (re)use 0-MALE, 1-FEMALE for range index
|
106
|
+
|
107
|
+
checks = 2 + randomUint(id, 1) % (SPRITESHEET_RANGES.size - 3) ## Number of bytes to check
|
108
|
+
|
109
|
+
checks.times do |i|
|
110
|
+
newAttribute = randomUint(id, 2+i) % (SPRITESHEET_RANGES.size - 2) + 1 ## Skip base category
|
111
|
+
|
112
|
+
next if attributes.include?( newAttribute )
|
113
|
+
attributes << newAttribute if SPRITESHEET_RANGES[newAttribute][gender].size != 0
|
114
|
+
end
|
115
|
+
|
116
|
+
attributes
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# function getAttributes(uint256 id) public view returns (uint256[] memory) {
|
121
|
+
# uint256[] memory attributeCategories = getAttributeCategories(id);
|
122
|
+
# uint256[] memory layers = new uint256[](attributeCategories.length);
|
123
|
+
# for (uint256 i = 0; i < attributeCategories.length; i++) {
|
124
|
+
# layers[i] = getAttribute(id, attributeCategories[i]);
|
125
|
+
# }
|
126
|
+
# return layers;
|
127
|
+
# }
|
128
|
+
|
129
|
+
def self.getAttributes( id )
|
130
|
+
getAttributeCategories( id ).map do |attributeCategory|
|
131
|
+
getAttribute( id, attributeCategory )
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
### add a extra/bonus helper for attribute metadata names
|
136
|
+
def self.getAttributeNames( id )
|
137
|
+
## note: MUST sort first for correct rendering order!!!
|
138
|
+
getAttributes( id ).sort.map do |attribute|
|
139
|
+
SPRITESHEET_ATTRIBUTES[attribute]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
# // Entropy 10
|
148
|
+
# function getAttribute(uint256 id, uint256 _attributeId) public view returns (uint256) {
|
149
|
+
# uint256[4] memory ranges = assets.spritesheetRanges()[_attributeId];
|
150
|
+
# Gender gender = getGender(id);
|
151
|
+
# if (gender == Gender.Female) {
|
152
|
+
# return ranges[1] + randomUint(id, 10+_attributeId) % (ranges[3] - ranges[1]);
|
153
|
+
# } else {
|
154
|
+
# return ranges[0] + randomUint(id, 10+_attributeId) % (ranges[2] - ranges[0]);
|
155
|
+
# }
|
156
|
+
# }
|
157
|
+
|
158
|
+
|
159
|
+
## Entropy 10
|
160
|
+
def self.getAttribute( id, attributeId )
|
161
|
+
gender = getGender( id )
|
162
|
+
range = SPRITESHEET_RANGES[attributeId][ gender ]
|
163
|
+
range.begin + randomUint( id, 10+attributeId ) % range.size
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
# // Entropy 0
|
168
|
+
# function getGender(uint256 id) public view returns (Gender) {
|
169
|
+
# return randomUint(id, 0) % 2 == 0 ? Gender.Male : Gender.Female;
|
170
|
+
# }
|
171
|
+
|
172
|
+
## Entropy 0
|
173
|
+
def self.getGender( id )
|
174
|
+
randomUint( id, 0 ) % 2 == 0 ? GENDER_MALE : GENDER_FEMALE
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
## note: address is really a uint160 number
|
179
|
+
## 160bit (is 20 bytes is 40 hexdigits)
|
180
|
+
## convert to addr_to_uint
|
181
|
+
## is really just hex_to_int (hexstring to big integer)
|
182
|
+
|
183
|
+
## do the "on-chain" pure method in ruby here "off-chain"
|
184
|
+
#
|
185
|
+
# function getTokenID(address _address) public pure returns (uint256) {
|
186
|
+
# return uint256(uint160(_address));
|
187
|
+
# }
|
188
|
+
|
189
|
+
## note: (ethereum) address as hexstring (160 bit/20 bytes/40 hexdigits)
|
190
|
+
## e.g. 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322
|
191
|
+
def self.getTokenID( address )
|
192
|
+
address.to_i( 16 )
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
# Non-standard Packed Mode
|
197
|
+
# Through abi.encodePacked(),
|
198
|
+
# Solidity supports a non-standard packed mode where:
|
199
|
+
#
|
200
|
+
# types shorter than 32 bytes are concatenated directly,
|
201
|
+
# without padding or sign extension
|
202
|
+
|
203
|
+
# // note:
|
204
|
+
# // address(this) is the address of the contract itself.
|
205
|
+
# // this keyword refers to the instance of a Contract.
|
206
|
+
ADDRESS = '0xaf9CE4B327A3b690ABEA6F78eCCBfeFFfbEa9FDf'
|
207
|
+
|
208
|
+
## note:
|
209
|
+
## returns a random unit number between 0-255 (0-ff)
|
210
|
+
## use offset (0-31),that is, byte out of byte32 entropy buffer/hash
|
211
|
+
|
212
|
+
def self.randomUint( seed, offset )
|
213
|
+
## assert( offset < 32, "Offset out of bounds")
|
214
|
+
## 256bit hash (= 32 bytes)
|
215
|
+
entropy = keccak256( hex_to_bin( ADDRESS ) +
|
216
|
+
hex_to_bin( uint256_to_hex(seed)) )
|
217
|
+
|
218
|
+
|
219
|
+
## convert binary bytes32 buffer to unint256 (big int)
|
220
|
+
## uint256 = bin_to_hex(entropy).to_i(16)
|
221
|
+
|
222
|
+
# mask = 0xff << (offset*8)
|
223
|
+
# out = (uint256 & mask) >> (offset*8)
|
224
|
+
# out
|
225
|
+
|
226
|
+
## note: pick a uint/byte (shorter version)
|
227
|
+
bytes = entropy.bytes.reverse
|
228
|
+
# puts "(random) 32 bytes (from 0 to 31):"
|
229
|
+
# pp bytes
|
230
|
+
bytes[offset]
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
########
|
235
|
+
## hex-to-bin/bin-to-hex helpers
|
236
|
+
def self.uint256_to_hex( num ) ## 256 bit (=32 bytes/64 hexdigits)
|
237
|
+
## note: adds padding that is leading zeros
|
238
|
+
"0x%064x" % num
|
239
|
+
end
|
240
|
+
|
241
|
+
# puts 'unit256_to_hex:'
|
242
|
+
# pp uint256_to_hex( 699372119169819039191610289391678040975564001026 )
|
243
|
+
#=> "0x0000000000000000000000007a80ee32044f496a7bfef65af738fdda3a02cf02"
|
244
|
+
|
245
|
+
def self.hex_to_bin( hex )
|
246
|
+
raise TypeError, "Value must be an instance of String" unless hex.instance_of?( String )
|
247
|
+
## remove/strip hex prefix e.g. 0x/0X
|
248
|
+
hex = hex[2..-1] if hex.start_with?( '0x' ) ||
|
249
|
+
hex.start_with?( '0X' )
|
250
|
+
[hex].pack("H*")
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.bin_to_hex( bin )
|
254
|
+
raise TypeError, "Value must be an instance of String" unless bin.instance_of?( String )
|
255
|
+
bin.unpack("H*").first
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.keccak256( bin )
|
259
|
+
Digest::KeccakLite.new(256).digest( bin )
|
260
|
+
end
|
261
|
+
end # module Synthpunks
|
262
|
+
|
263
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module Synthpunks
|
3
|
+
|
4
|
+
|
5
|
+
class Image < Pixelart::Image
|
6
|
+
def self.generate( addr )
|
7
|
+
puts "==> generate SyntheticPunk for #{addr}..."
|
8
|
+
token_id = Synthpunks.getTokenID( addr )
|
9
|
+
## note: MUST sort for correct rendering order
|
10
|
+
puts " using (derived) token_id >#{token_id}<"
|
11
|
+
attributes = Synthpunks.getAttributes( token_id ).sort
|
12
|
+
puts " using (pseudo-random derived) attributes >#{attributes}<:"
|
13
|
+
attributes.each do |attribute|
|
14
|
+
puts " #{attribute} => #{SPRITESHEET_ATTRIBUTES[attribute]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
img = new( 24, 24 )
|
18
|
+
attributes.each do |attribute|
|
19
|
+
img.compose!( SPRITESHEET[ attribute ] )
|
20
|
+
end
|
21
|
+
img
|
22
|
+
end
|
23
|
+
end # class Image
|
24
|
+
end # module Synthpunks
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module Pixelart
|
3
|
+
module Module
|
4
|
+
module Synthpunks
|
5
|
+
|
6
|
+
MAJOR = 0
|
7
|
+
MINOR = 0
|
8
|
+
PATCH = 1
|
9
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
10
|
+
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.banner
|
16
|
+
"synthpunks/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.root
|
20
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
21
|
+
end
|
22
|
+
|
23
|
+
end # module Synthpunks
|
24
|
+
end # module Module
|
25
|
+
end # module Pixelart
|
26
|
+
|
data/lib/synthpunks.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'pixelart'
|
2
|
+
require 'ethlite' ## needed for Digest::Keccak (otherwise no dep for now)
|
3
|
+
|
4
|
+
|
5
|
+
## our own code
|
6
|
+
require_relative 'synthpunks/version'
|
7
|
+
require_relative 'synthpunks/contract'
|
8
|
+
require_relative 'synthpunks/image'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## add some alternate names / aliases - why? why not?
|
13
|
+
Synthpunk = Synthpunks
|
14
|
+
Syntheticpunk = Synthpunks
|
15
|
+
Syntheticpunks = Synthpunks
|
16
|
+
SynthPunk = Synthpunks
|
17
|
+
SynthPunks = Synthpunks
|
18
|
+
SyntheticPunk = Synthpunks
|
19
|
+
SyntheticPunks = Synthpunks
|
20
|
+
|
21
|
+
|
22
|
+
puts Pixelart::Module::Synthpunks.banner # say hello
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: synthpunks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pixelart
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.3.6
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.3.6
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: etherlite
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '7'
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '4.0'
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '7'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: hoe
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.23'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.23'
|
75
|
+
description: synthpunks - (free unlimited) 24×24 pixel punks for everyone - yes, you
|
76
|
+
can - generate / claim your own synth(etic) punks ("off-blockchain") for your own
|
77
|
+
(ethereum) account 40-hexdigit addresses e.g. 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322;
|
78
|
+
incl. 2x/4x/8x zoom for bigger sizes
|
79
|
+
email: wwwmake@googlegroups.com
|
80
|
+
executables: []
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files:
|
83
|
+
- CHANGELOG.md
|
84
|
+
- Manifest.txt
|
85
|
+
- README.md
|
86
|
+
files:
|
87
|
+
- CHANGELOG.md
|
88
|
+
- Manifest.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- config/spritesheet.json
|
92
|
+
- config/spritesheet.png
|
93
|
+
- lib/synthpunks.rb
|
94
|
+
- lib/synthpunks/contract.rb
|
95
|
+
- lib/synthpunks/image.rb
|
96
|
+
- lib/synthpunks/version.rb
|
97
|
+
homepage: https://github.com/cryptopunksnotdead/cryptopunks
|
98
|
+
licenses:
|
99
|
+
- Public Domain
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options:
|
103
|
+
- "--main"
|
104
|
+
- README.md
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '2.3'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubygems_version: 3.3.7
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: synthpunks - (free unlimited) 24×24 pixel punks for everyone - yes, you can
|
122
|
+
- generate / claim your own synth(etic) punks ("off-blockchain") for your own (ethereum)
|
123
|
+
account 40-hexdigit addresses e.g. 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322; incl.
|
124
|
+
2x/4x/8x zoom for bigger sizes
|
125
|
+
test_files: []
|