Jang.js is a Javascript tool used to create custom artwork for NFT collections. There were lots of simple NFT generators that created collections based on the images in a directory but I wanted the ability to add custom logic when building up artwork layers.
Blog post covering this tool here: https://jamesbachini.com/how-to-generate-artwork-for-nfts/
You'll need Node.js installed from https://nodejs.org
Then open up a terminal/console and clone the directory and install dependencies.
git clone https://github.com/jamesbachini/JANG-Just-Another-NFT-Generator.git
cd JANG-Just-Another-NFT-Generator/
npm install
From there you can open up jang.js in a text editor and change the project name, description, URL etc.
Once you have the basic settings done it's time to start creating layers. Start with a background or collection of backgrounds and then build on top of that. All the code after /* Add layers using various methods here */ can be modified to suit your individual project.
The layer is added using the following command. The first parameter should be the directory the layers are stored in i.e layers/Backgrounds, the second parameter should be the filename without the .png, this is also written to the metadata file for the NFT so name it something descriptive, the final parameter is constant and we just pass a pointer to the canvas object as ctx.
await addLayer('Backgrounds', 'Background1', ctx);
Random from array
const arr = ['Background1','Background2','Background3','Background4'];
const bkg = arr[Math.floor(Math.random()*arr.length)];
await addLayer('Backgrounds', bkg, ctx);
Generating playing cards from nftID (can be used in the smart contract too)
// Numbers
const cardNumber = nftID % 13 + 1;
await addLayer('Numbers', cardNumber, attributes, ctx);
// Suits
const suitRef = nftID % 4;
const arr = ['Spades','Hearts','Diamonds','Clubs'];
const suit = arr[suitRef];
await addLayer('Suits', suit, attributes, ctx);
Custom rarity with some randomness
let character = 'Jack';
if (Math.random() > 0.7) character = 'Jill';
if (Math.random() > 0.99) character = 'James';
await addLayer('Characters', character, ctx);
Super rare one offs (Will front-load the rare NFT's to earlier ID's)
const arr = ['Human','Ape','Mutant','Punk','Loogie']; // put this array outside of the loop at the top of the script
const attr = arr[Math.floor(Math.random()*arr.length)];
if (attr === 'Punk') arr.splice(3,1); // removes Punk at array index 3 (starts at 0) out of the array
await addLayer('AvatarType', attr, ctx);
Super rare one offs better method
const arr = ['Human','Ape','Mutant','Punk','Loogie'];
let attr = arr[Math.floor(Math.random()*arr.length)];
const alienID = Math.floor(Math.random() * 10000);
if (nftID === alienID) attr = 'Alien';
await addLayer('AvatarType', attr, ctx);
Specific traits for specific ID's
const arr = ['Happy','Sad'];
let mouth = arr[Math.floor(Math.random()*arr.length)];
if (nftID.toString().includes(420)) mouth = 'Smoking';
await addLayer('Eyes', mouth, ctx);
Add Numeric Attributes With No Image Layers
const strength = Math.floor(Math.random()*99);
ctx.attributes.push({ 'trait_type': 'Strength', 'value': strength });
Add an image layer or filter but no attribute
const img = await canvas.loadImage(`${dir.input}/vignette.png`);
ctx.drawImage(img,0,0,imageSize.width,imageSize.height);
Feel free to add more examples above this line via a pull request.
The generator outputs two directories output/hdimages/ and output/images/
The HD images are the raw output of the generator. The output/images directory holds compressed images.
Compression is useful as uploading 10,000 high res images to IPFS is about as much fun as [redacted].
You can change the compression settings to make the images higher quality or lower file size.
High Quality Larger Size
plugins: [imageminPngquant({quality: [0.5, 0.7]})]
Low Quality Smaller Size
plugins: [imageminPngquant({quality: [0.3, 0.5]})]
More options and spec here: https://github.com/imagemin/imagemin-pngquant#readme
There's more info on blockchain development and NFT's on my blog at https://jamesbachini.com
To upload your NFT's to IPFS check out https://nft.storage or https://www.pinata.cloud/
For creating the smart contract check out OpenZepellin's ERC721 token library and documentation: https://docs.openzeppelin.com/contracts/4.x/erc721
For compiling and deploying the contract you can use https://remix.ethereum.org