This is a tool for creating, evaluating and uploading nft images.
npm install
npm start-generator
This NFT-Generator was build to support multiple projects with multiple collections. This is the reason why there can be multiple config files.
The config.json
is located in the root folder. This config is shared accross all projects:
projectsGlob
The glob to identify where the project folders are located.nftStorageApiKey
The api key used to upload the nft images.
A project can have multiple collections. This Is the collection specific configuration.
interface RawConfigFile {
name: string; // name of your project
amount: number; // amount of nfts to generate
assets: {
outputPath: string; // output path of image files
inputPath: string; // path of the directory which holds the folder with the input images
order: string[]; // the layering order of the input images. e.g.: ["Background", "Skin", "Mouth"] (not case sensitive)
outputSize?: Size; // output size of the nft image (Default: original size)
fileExtensions?: string[]; // array of supported input image extensions (Default: ['png', 'jpg', 'jpeg'])
restrictions?: Record<string, RestrictionItem[]>; // restrictions which apply for each image
};
schema?: {
outputPath: string; // output path of json files
attributesKey: string; // the field name of the attributes field of the output json
format: {
name: string; // the name field of the output json
[key: string]: unknown; // any other key - value pair allowed here
};
};
rarityCollection?: {
outputPath: string; // the output path of the rarity collection json file (if not present rarity collection won't run)
};
}
Any field which is in the root scope of the json can be used as variable inside the rest of the config.
You can also add custom fields into the root scope to define your own variables.
Additionally there are two "special" variables called index
and totalIndex
.
index
is the current iteration index of the current collectiontotalIndex
is the current iteration index of all collections (is same asindex
if you run only one collection)
You can also write pure javascript to maximize customization.
This config:
{
"name": "NFT-Project-XY",
"amount": 1,
"executionDate": "{Date.now()}",
"assets": {
"outputPath": "./Output/{name}/image/image {index +1} of {amount} - #{executionDate}.png",
"inputPath": "./Input/{name}"
}
}
Will evaluate to:
{
"name": "NFT-Project-XY",
"amount": 1,
"executionDate": "1649725612780",
"assets": {
"outputPath": "./Output/NFT-Project-XY/image/image 1 of 1 - #1649725612780.png",
"inputPath": "./Input/NFT-Project-XY"
}
}
The order
array in the assets
object relates to the image directories which should be included.
{
"assets": {
"inputPath": "./Input/{name}",
"order": ["background", "skin", "mouth"]
}
}
Would include all the images of the directories:
./Input/{name}/background
./Input/{name}/skin
./Input/{name}/mouth
Note: the directory names in the order
array are case insensitive. It doesn't matter if you write background
or Background
as long as there is a folder with this name it will be picked up.
You can add image restrictions to your layers with the restrictions
option.
{
"restrictions": {
// a object with keys which must match one of the foldernames provided in the order option
"background": [
// here starts the restrictions of the "background" layer
{
"matches": ["*transparent*"], // if the background image name matches this set of globs...
// ...all of the following restrictions apply to the following layers:
"choose": {
"skin": ["hairy*", "soft*"], // the skin layer will act like only images which matches those globs are available
"mouth": ["open*"] // the mouth layer will act like only images which matches those globs are available
// not specified layers have no restrictions
}
}
]
}
}
Use ["*"]
to remove all restrictions explicitly:
{
"restrictions": {
"background": [
{
"matches": ["*transparent*"],
"choose": {
"skin": ["hairy*", "soft*"],
"mouth": ["open*"] // mouth is restricted
}
}
],
"skin": [
{
"matches": ["soft*"],
"choose": {
"mouth": ["*"] // mouth restriction is removed
}
}
]
}
}
In the above example even though the mouth
layer was restricted to ["open*"]
, the restriction was removed if the skin
images matches the soft*
glob.
Instead of removing the restriction it can also be changed to something else.
Use null
to remove the layer from generation:
{
"restrictions": {
"background": [
{
"matches": ["*transparent*"],
"choose": {
"skin": ["hairy*", "soft*"],
"mouth": null
}
}
]
}
}
In this example the mouth
layer is not included in the image generation, so the final images simply won't have a mouth
layer.
All of the field names which have to correspond to a value in the order
array, and the glob patterns are case insensitive.
Layers removed with this option won't appear in the schema.json
except if you specify the restrictionRemovedAttributeValue
field to a string which will replace the attribute value for that layer.
You can create and customize animated gif sequences of your generated images with the previewAnimation
section.
{
"previewAnimation": {
"quantity": 1, // the amount of gif animations to generate (in case you don't like the first)
"sampleSize": 10, // specifies the slide amount of your gif
"outputPath": "./Output/{name}/preview {index +1} of {quantity}.gif", // output path, has to be specified
"animation": {
"delay": 800, // time in ms until the image changes in the animation.
"repeat": 0, // repeat count of the animation. 0 means infinity.
"quality": 10 // quality of the animation.
},
"outputSize": {
"width": 1024, // the width of the animation (defaults to your generated images width)
"height": 1024 // the height of the animation (defaults to your generated images height)
}
}
}