diff --git a/README.md b/README.md index 7c3e32e7..dff134da 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,16 @@ $ npm run rarity_rank - Provides ranking details through a user interface after calculating using the codeSTACKr Rarity command. +Rarity Layer (codeSTACKr): +``` +$ npm run add_rarity_layer +``` + +- Adds an additional layer for rarity decals based on the rarity rating assigned by the rarity calculation. (It requires the rarity metadata file to have been generated.) +- Configurable via `rarity_layer/config.js` and uses assets relative to this directory. +- It creates new files in the image directory in build directory with a distinct name e.g. `1_.png, 2_.png...` to allowing you to preview the results and rerun the command with a different configuration if the results are unsatisfactory. +- Run `npm run merge_rarity_layer` to finalize. + Update Info: ``` $ npm run update_info diff --git a/package.json b/package.json index a2326317..ab336826 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "rarity": "node utils/rarity", "rarity_md": "node utils/functions/getRarity_fromMetadata", "rarity_rank": "node utils/functions/rarity_rank.js", + "add_rarity_layer": "node utils/functions/add_rarity_layer.js", + "merge_rarity_layer": "node utils/functions/merge_rarity_layer.js", "preview": "node utils/preview.js", "pixelate": "node utils/pixelate.js", "update_info": "node utils/update_info.js", diff --git a/rarity_layer/circle.png b/rarity_layer/circle.png new file mode 100644 index 00000000..9d0da15e Binary files /dev/null and b/rarity_layer/circle.png differ diff --git a/rarity_layer/config.js b/rarity_layer/config.js new file mode 100644 index 00000000..14a5818f --- /dev/null +++ b/rarity_layer/config.js @@ -0,0 +1,18 @@ +// Offsets for where to place the rarity image from the top left corner of the image. +const offset_x = 10; +const offset_y = 10; + +// This uses the highest rarity image it can based on thresholds +// (This list need not be in order) +const rarity_thresholds = [ + { threshold: 120, image: "cross.png" }, + { threshold: 90, image: "square.png" }, + { threshold: 30, image: "triangle.png" }, + { threshold: 0, image: "circle.png" }, +]; + +module.exports = { + offset_x, + offset_y, + rarity_thresholds, +}; diff --git a/rarity_layer/cross.png b/rarity_layer/cross.png new file mode 100644 index 00000000..c2ea858e Binary files /dev/null and b/rarity_layer/cross.png differ diff --git a/rarity_layer/square.png b/rarity_layer/square.png new file mode 100644 index 00000000..f29d2092 Binary files /dev/null and b/rarity_layer/square.png differ diff --git a/rarity_layer/triangle.png b/rarity_layer/triangle.png new file mode 100644 index 00000000..aa3b7626 Binary files /dev/null and b/rarity_layer/triangle.png differ diff --git a/utils/functions/add_rarity_layer.js b/utils/functions/add_rarity_layer.js new file mode 100644 index 00000000..e673a3b0 --- /dev/null +++ b/utils/functions/add_rarity_layer.js @@ -0,0 +1,64 @@ +const basePath = process.cwd(); +const fs = require("fs"); +const { createCanvas, loadImage } = require(`${basePath}/node_modules/canvas`); + +const { + offset_x, + offset_y, + rarity_thresholds, +} = require(`${basePath}/rarity_layer/config`); + +const rarity_decals = rarity_thresholds.sort( + (a, b) => b.threshold - a.threshold +); + +(async () => { + try { + let rarity_decals = []; + const decal_thresholds = rarity_thresholds.sort( + (a, b) => b.threshold - a.threshold + ); + for (let i = 0; i < decal_thresholds.length; i++) { + rarity_decals.push({ + imageData: await loadImage(`${basePath}/rarity_layer/${decal_thresholds[i].image}`), + threshold: decal_thresholds[i].threshold, + }); + } + + if (!fs.existsSync(`${basePath}/build/json/_metadata_with_rarity.json`)) + throw new Error( + "_metadata_with_rarity.json not found, please run `npm run rarity_md` first" + ); + const startAt0 = fs.existsSync(`${basePath}/build/images/0.png`); + if (!startAt0 && !fs.existsSync(`${basePath}/build/images/1.png`)) + throw new Error("no images found"); + // read json data + const rawdata = fs.readFileSync( + `${basePath}/build/json/_metadata_with_rarity.json` + ); + const nfts = JSON.parse(rawdata); + + for (let i = startAt0 ? 0 : 1; i < nfts.length + (startAt0 ? 0 : 1); i++) { + const nft = nfts[i - (startAt0 ? 0 : 1)]; + const rarity = nft.total_rarity_score; + const imagePath = `${basePath}/build/images/${i}.png`; + const image = await loadImage(imagePath); + const canvas = createCanvas(image.width, image.height); + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, 0, 0); + for (let j = 0; j < rarity_decals.length; j++) { + if (rarity_decals[j].threshold < rarity) { + ctx.drawImage(rarity_decals[j].imageData, offset_x, offset_y); + break; + } + } + const newImagePath = `${basePath}/build/images/${i}_.png`; + canvas.toBuffer((err, buf) => { + if (err) throw err; + fs.writeFileSync(newImagePath, buf); + }); + } + } catch (e) { + console.error("unable to complete", e); + } +})(); diff --git a/utils/functions/merge_rarity_layer.js b/utils/functions/merge_rarity_layer.js new file mode 100644 index 00000000..1ad8ceb7 --- /dev/null +++ b/utils/functions/merge_rarity_layer.js @@ -0,0 +1,10 @@ +const basePath = process.cwd(); +const fs = require("fs"); + +const files = fs.readdirSync(`${basePath}/build/images`); +for (let i = 0; i < files.length; i++) { + if (files[i].includes("_")) { + const filename = `${basePath}/build/images/${files[i]}` + fs.renameSync(filename, filename.replace("_", "")); + } +}