synthpunks 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2022-12-06
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,10 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ config/spritesheet.json
6
+ config/spritesheet.png
7
+ lib/synthpunks.rb
8
+ lib/synthpunks/contract.rb
9
+ lib/synthpunks/image.rb
10
+ lib/synthpunks/version.rb
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: []