Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ee78b0e
resetNameIndex fix
bruceballad Oct 24, 2021
86fa0c0
Improvements
bruceballad Oct 24, 2021
89b17cf
Improvements part-2
bruceballad Oct 24, 2021
8a78b3b
New removeMetadataContent utility
bruceballad Oct 24, 2021
649e158
Merge branch 'nftchef:nested-folder-structure' into nested-folders-im…
bruceballad Oct 25, 2021
1a9fc9e
Merge branch 'nftchef:nested-folder-structure' into nested-folders-im…
bruceballad Oct 28, 2021
17fbecf
Delete 3shadow?blend=multiply&opacity=50.png
bruceballad Oct 29, 2021
f4656f6
Changes based on the requests from nftchef
bruceballad Oct 29, 2021
d912608
Merge branch 'nested-folder-structure' into nested-folders-improvemen…
bruceballad Nov 3, 2021
c9d4fa9
small comment clean up.
bruceballad Nov 3, 2021
d509238
Merge branch 'nftchef:nested-folder-structure' into nested-folders-im…
bruceballad Nov 6, 2021
978c1b7
Merge branch 'nftchef:nested-folder-structure' into nested-folders-im…
bruceballad Nov 10, 2021
fc45eb1
Merge branch 'nftchef:nested-folder-structure' into nested-folders-im…
bruceballad Nov 11, 2021
70b9cd4
Fix for using createPreviewCollage.js with JPEG outputs
bruceballad Nov 16, 2021
a4c6c8d
fix _offset console message + edition reports with name
bruceballad Nov 16, 2021
a38859d
Fix for using updateBaseUri.js with JPEG outputs
bruceballad Nov 16, 2021
064e4b7
adds bypass DNA
bruceballad Nov 21, 2021
328829c
Merge branch 'nested-folder-structure' into nested-folders-improvemen…
bruceballad Nov 21, 2021
3fc7161
Merge branch 'nested-folder-structure' into nested-folders-improvemen…
bruceballad Jan 2, 2022
3d139dc
Small Update
bruceballad Jan 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 83 additions & 38 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,46 @@ const buildDir = path.join(basePath, "/build");
const layersDir = path.join(basePath, "/layers");

const description =
"This is the description of your NFT project, remember to replace this";
"Default Description";
const baseUri = "ipfs://NewUriToReplace";

const baseExternalUrl = "https://test.com/collection?asset="; //Base url for extelnal link under the image on OpenSea. The edition number will be appended. Leave empty "" to remove. - BB

const outputJPEG = false; // if false, the generator outputs png's

// if you use an empty/transparent file, set the name here.
const emptyLayerName = "NONE";

//IF you need a provenance hash, turn this on
//IF you need a provenance hash, turn this on
const hashImages = true;

const layerConfigurations = [

{
growEditionSizeTo: 11,
// namePrefix: "Monkey", Use to add a name to Metadata `name:`
growEditionSizeTo: 10,
descriptionOverwrite: " with Unique Description For Layer Set A", // for layerSet spesific descriptions. Here, it is written in a way to suit the names that will be prepended.
prependNameInDescription: true, // add/prepend asset name to the description. - BB
namePrefix: "Monkey",
resetNameIndex: true, // this will start the count at #1 for this layerconfig
nameSuffix: "Set A", // add a suffix after the number. if resetNameIndex is on too, put the reseted counter after the suffix - BB
layersOrder: [
{ name: "Back Accessory" },
{ name: "Head" },
{ name: "Clothes" },
{ name: "Eyes" },
{ name: "Hair" },
{ name: "Head Accessory" },
{ name: "Shirt Accessories" },
],
},

{
growEditionSizeTo: 20,
descriptionOverwrite: " with Unique Description For Layer Set A", // for layerSet spesific descriptions. Here, it is written in a way to suit the names that will be prepended.
prependNameInDescription: true, // add/prepend asset name to the description. - BB
namePrefix: "Monkey",
resetNameIndex: true, // this will start the count at #1 for this layerconfig
nameSuffix: "Set B", // add a suffix after the number. if resetNameIndex is on too, put the reseted counter after the suffix - BB
layersOrder: [
{ name: "Back Accessory" },
{ name: "Head" },
Expand All @@ -34,19 +59,10 @@ const layerConfigurations = [
{ name: "Shirt Accessories" },
],
},
// {
// growEditionSizeTo: 10,
// namePrefix: "Lion",
// resetNameIndex: true, // this will start the Lion count at #1 instead of #6
// layersOrder: [
// { name: "Background" },
// { name: "Hats" },
// { name: "Male Hair" },
// ],
// },
];

/**

/**
* Incompatible items can be added to this object by a files cleanName
* This works in layer order, meaning, you need to define the layer that comes
* first as the Key, and the incompatible items that _may_ come after.
Expand All @@ -59,7 +75,8 @@ const incompatible = {
// White: ["rare-Pink-Pompadour"],
};

/**

/**
* Require combinations of files when constructing DNA, this bypasses the
* randomization and weights.
*
Expand All @@ -68,8 +85,10 @@ const incompatible = {
* the items in the array are "required" items that should be pulled from folders
* further in the stack
*/

const forcedCombinations = {
floral: ["MetallicShades", "Golden Sakura"],
// Force some layers if a certain layer is used.
//floral: ["MetallicShades", "Golden Sakura"],
};

const shuffleLayerConfigurations = false;
Expand All @@ -86,31 +105,56 @@ const background = {
brightness: "80%",
};

const extraMetadata = {};
const extraMetadata = {
// You can add extra info for your collection here. Such as the artist name.
"Artist": "A person",
};

const extraAttributes = () => [

//OpenSea Trait Types for rich data = https://docs.opensea.io/docs/metadata-standards
//These are just examples to show dynamic uses. Delete all these if they do not fiy in your project.
{
display_type: "boost_percentage", // Boost trait with lightning icon. Number is shown with a % sign. Circle fill by the percentage.
trait_type: "Health",
value: Math.floor(Math.random() * 100),
},
{
display_type: "boost_number", // Boost trait with lightning icon. Number is shown with a + sign. Circle is filled.
trait_type: "Energy",
value: Math.floor(Math.random() * 100),
},
{
display_type: "number", // Appears in the "Stats" area with a large number. "Out of X" value is taken from the collection.
trait_type: "Mana",
value: Math.floor(Math.random() * 100),
},
{
//Integer value with no display_type set makes the trait appear in the "Rankings" area with a progress bar. Max value is taken from the collection.
trait_type: "Rank",
value: Math.floor(Math.random() * 100),
},

{
//display_type date makes a date section appear in the right column near "Rankings" and "Stats."
display_type: "date",
trait_type: "Birthday",

// Give a random date between;
// Unix Timestamp 1609455600 (GMT Thu Dec 31 2020 23:00:00 GMT+0000) and
// Unix Timestamp 631148400 (GMT Sun Dec 31 1989 23:00:00 GMT+0000)
value: (Math.floor( Math.random() * (1609455634 - 631148434) ) + 631148434)
},

{
//String value with no display_type set makes the trait appear in the "Properties" area like layers.
trait_type: "Familly",
value: `Familly #${ Math.floor(Math.random() * (6 - 1 + 1) ) + 1 }`, // Math.floor(Math.random() * (max - min + 1) ) + min; // min max included
}

// Optionally, if you need to overwrite one of your layers attributes.
// You can include the same name as the layer, here, and it will overwrite
//
// {
// trait_type: "Bottom lid",
// value: ` Bottom lid # ${Math.random() * 100}`,
// },
// {
// display_type: "boost_number",
// trait_type: "Aqua Power",
// value: Math.random() * 100,
// },
// {
// display_type: "boost_number",
// trait_type: "Health",
// value: Math.random() * 100,
// },
// {
// display_type: "boost_number",
// trait_type: "Mana",
// value: Math.floor(Math.random() * 100),
// },

];

const rarityDelimiter = "#";
Expand All @@ -129,6 +173,7 @@ module.exports = {
layersDir,
format,
baseUri,
baseExternalUrl,
description,
background,
uniqueDnaTorrance,
Expand Down
51 changes: 45 additions & 6 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const {
layersDir,
format,
baseUri,
baseExternalUrl,
description,
background,
uniqueDnaTorrance,
Expand Down Expand Up @@ -91,7 +92,7 @@ const getElements = (path, layer) => {
const extension = /\.[0-9a-zA-Z]+$/;
const sublayer = !extension.test(i);
const weight = getRarityWeight(i);

const blendMode = layer.blend != undefined ? layer.blend : "source-over";
const opacity = layer.opacity != undefined ? layer.opacity : 1;

Expand Down Expand Up @@ -186,8 +187,15 @@ const drawBackground = () => {

const addMetadata = (_dna, _edition, _prefixData) => {
let dateTime = Date.now();
const { _prefix, _offset, _imageHash } = _prefixData;

const {
_descriptionOverwrite,
_prependNameInDescription,
_prefix,
_offset,
_suffix,
_imageHash
} = _prefixData;

const combinedAttrs = [...attributesList, ...extraAttributes()];
const cleanedAttrs = combinedAttrs.reduce((acc, current) => {
const x = acc.find((item) => item.trait_type === current.trait_type);
Expand All @@ -200,9 +208,18 @@ const addMetadata = (_dna, _edition, _prefixData) => {

let tempMetadata = {
dna: hash(_dna),
name: `${_prefix ? _prefix + " " : ""}#${_edition - _offset}`,
description: description,

// New name builder. It can form names like; "PREFIX #10 - SUFFIX #2". - BB
name: `${_prefix ? _prefix + " " : ""}#${_suffix ? _edition : _edition - _offset}${_suffix ? " " + _suffix + (_offset>0 ? " #" + (_edition - _offset) : "") : ""}`,

// new description builder, it can prepends the asset name, AND overwrite the description for different layerConfigs. Can form unique descriptions like; "Item #10 is an art piece from Collection X". - BB
description: `${_prependNameInDescription ? `${_prefix ? _prefix + " " : ""}#${_suffix ? _edition : _edition - _offset}${_suffix ? " " + _suffix + (_offset>0 ? " #" + (_edition - _offset) : "") : ""}` : ""}${_descriptionOverwrite ? _descriptionOverwrite : description}`,

// Adds external_url if the baseExternalUrl in config is not empty, combines it with edition numbers. - BB
...(baseExternalUrl !== "" && { external_url: `${baseExternalUrl}${_edition}` }),

image: `${baseUri}/${_edition}${outputJPEG ? ".jpg" : ".png"}`,

...(hashImages === true && { imageHash: _imageHash }),
edition: _edition,
date: dateTime,
Expand Down Expand Up @@ -542,26 +559,48 @@ const startCreating = async () => {
}`
);
const _imageHash = hash(savedFile);

// if there's a descriptionOverwrite for the current layerConfig, then
// use that description in the assets - BB
const _descriptionOverwrite = layerConfigurations[layerConfigIndex].descriptionOverwrite
? layerConfigurations[layerConfigIndex].descriptionOverwrite
: null;

// prependNameInDescription - BB
const _prependNameInDescription = layerConfigurations[layerConfigIndex].prependNameInDescription;

// if there's a prefix for the current configIndex, then
// start count back at 1 for the name, only.
const _prefix = layerConfigurations[layerConfigIndex].namePrefix
? layerConfigurations[layerConfigIndex].namePrefix
: null;

// if resetNameIndex is turned on, calculate the offset and send it
// with the prefix
let _offset = 0;
if (layerConfigurations[layerConfigIndex].resetNameIndex) {
_offset = layerConfigurations.reduce((acc, layer, index) => {
if (index < layerConfigIndex) {
acc += layer.growEditionSizeTo;
acc = layer.growEditionSizeTo;
return acc;
}
return acc;
}, 0);
}

// if there's a suffix for the current configIndex, then
// add it after the counter number
// if resetNameIndex is on too, the resetted counter will be added after the suffix
const _suffix = layerConfigurations[layerConfigIndex].nameSuffix
? layerConfigurations[layerConfigIndex].nameSuffix
: null;

addMetadata(newDna, abstractedIndexes[0], {
_descriptionOverwrite, // BB
_prependNameInDescription, // BB
_prefix,
_offset,
_suffix,
_imageHash,
});

Expand Down
80 changes: 80 additions & 0 deletions utils/removeMetadataContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
---------------
This utility can be used for removing unwanted data from json files such as "dna" or "external_url".
Created by modifying removeTrait.js utility.
Use by running the following command;
```
node utils/removeMetadataContent.js "Background"
```
or for additional logging, use with the `-d` flag
```
node utils/removeMetadataContent.js "Background" -d
```
- BB
---------------
*/


"use strict";

const isLocal = typeof process.pkg === "undefined";
const basePath = isLocal ? process.cwd() : path.dirname(process.execPath);
const fs = require("fs");
const path = require("path");
const { Command } = require("commander");
const program = new Command();

const chalk = require("chalk");
const jsonDir = `${basePath}/build/json`;
const metadataFilePath = `${basePath}/build/json/_metadata.json`;

const getIndividualJsonFiles = () => {
return fs
.readdirSync(jsonDir)
.filter((item) => /^[0-9]{1,6}.json/g.test(item));
};

program
.argument("<target>")
.option("-d, --debug", "display some debugging")
.action((target, options, command) => {
const jsonFiles = getIndividualJsonFiles();
options.debug
? console.log(
`Found ${jsonFiles.length} json files in "${jsonDir}" to process`
)
: null;

console.log(chalk.greenBright.inverse(`Removing ${target}`));
jsonFiles.forEach((filename) => {
// read the contents
options.debug ? console.log(`removing ${target} from ${filename}`) : null;
const contents = JSON.parse(fs.readFileSync(`${jsonDir}/${filename}`));

const hasTarget = contents.hasOwnProperty(target);

if (!hasTarget) {
console.log(chalk.yellow(`"${target}" not found in ${filename}`));
}
// remove the target from attributes

delete contents[target]

// write the file
fs.writeFileSync(
`${jsonDir}/${filename}`,
JSON.stringify(contents, null, 2)
);

options.debug
? console.log(
hasTarget ? chalk.greenBright("Removed \n") : "…skipped \n"
)
: null;
});
});

program.parse();