Code missing something

thank you. what the best way to provide you with in info?

// utilise Moralis
const Moralis = require("moralis/node");
// canvas for image compile

const { createCanvas, loadImage } = require("canvas");
// import config
const {
  layers,
  width,
  height,
  description,
  baseImageUri,
  editionSize,
  startEditionFrom,
  rarityWeights,
} = require("./input/config.js");
const console = require("console");
const fs = require("fs");
const request = require("request");
const { default: axios } = require("axios");
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");


Moralis.start({ serverUrl, appId, masterKey });

// adds a signature to the top left corner of the canvas for pre-production
const signImage = (_sig) => {
  ctx.fillStyle = "#000000";
  ctx.font = "bold 30pt Helvetica";
  ctx.textBaseline = "top";
  ctx.textAlign = "left";
  ctx.fillText(_sig, 40, 40);
};

// generate a random color hue
const genColor = () => {
  let hue = Math.floor(Math.random() * 360);
  let pastel = `hsl(${hue}, 100%, 85%)`;
  return pastel;
};

const drawBackground = () => {
  ctx.fillStyle = genColor();
  ctx.fillRect(0, 0, width, height);
};

// add metadata for individual nft edition
const generateMetadata = (_dna, _edition, _attributesList, _path) => {
  let dateTime = Date.now();
  let tempMetadata = {
    dna: _dna.join(""),
    name: `#${_edition}`,
    description: description,
    image: _path || baseImageUri,
    edition: _edition,
    date: dateTime,
    attributes: _attributesList,
  };
  return tempMetadata;
};

// prepare attributes for the given element to be used as metadata
const getAttributeForElement = (_element) => {
  let selectedElement = _element.layer.selectedElement;
  let attribute = {
    name: selectedElement.name,
    rarity: selectedElement.rarity,
  };
  return attribute;
};

// loads an image from the layer path
// returns the image in a format usable by canvas
const loadLayerImg = async (_layer) => {
  return new Promise(async (resolve) => {
    const image = await loadImage(`${_layer.selectedElement.path}`);
    resolve({ layer: _layer, loadedImage: image });
  });
};

const drawElement = (_element) => {
  ctx.drawImage(
    _element.loadedImage,
    _element.layer.position.x,
    _element.layer.position.y,
    _element.layer.size.width,
    _element.layer.size.height
  );
};

// check the configured layer to find information required for rendering the layer
// this maps the layer information to the generated dna and prepares it for
// drawing on a canvas
const constructLayerToDna = (_dna = [], _layers = [], _rarity) => {
  let mappedDnaToLayers = _layers.map((layer, index) => {
    let selectedElement = layer.elements.find(
      (element) => element.id === _dna[index]
    );
    return {
      location: layer.location,
      position: layer.position,
      size: layer.size,
      selectedElement: { ...selectedElement, rarity: _rarity },
    };
  });
  return mappedDnaToLayers;
};

// check if the given dna is contained within the given dnaList
// return true if it is, indicating that this dna is already in use and should be recalculated
const isDnaUnique = (_DnaList = [], _dna = []) => {
  let foundDna = _DnaList.find((i) => i.join("") === _dna.join(""));
  return foundDna == undefined ? true : false;
};

const getRandomRarity = (_rarityOptions) => {
  let randomPercent = Math.random() * 100;
  let percentCount = 0;

  for (let i = 0; i <= _rarityOptions.length; i++) {
    percentCount += _rarityOptions[i].percent;
    if (percentCount >= randomPercent) {
      console.log(`use random rarity ${_rarityOptions[i].id}`);
      return _rarityOptions[i].id;
    }
  }
  return _rarityOptions[0].id;
};

// create a dna based on the available layers for the given rarity
// use a random part for each layer
const createDna = (_layers, _rarity) => {
  let randNum = [];
  let _rarityWeight = rarityWeights.find((rw) => rw.value === _rarity);
  _layers.forEach((layer) => {
    let num = Math.floor(
      Math.random() * layer.elementIdsForRarity[_rarity].length
    );
    if (_rarityWeight && _rarityWeight.layerPercent[layer.id]) {
      // if there is a layerPercent defined, we want to identify which dna to actually use here (instead of only picking from the same rarity)
      let _rarityForLayer = getRandomRarity(
        _rarityWeight.layerPercent[layer.id]
      );
      num = Math.floor(
        Math.random() * layer.elementIdsForRarity[_rarityForLayer].length
      );
      randNum.push(layer.elementIdsForRarity[_rarityForLayer][num]);
    } else {
      randNum.push(layer.elementIdsForRarity[_rarity][num]);
    }
  });
  return randNum;
};

// holds which rarity should be used for which image in edition
let rarityForEdition;

// get the rarity for the image by edition number that should be generated
const getRarity = (_editionCount) => {
  if (!rarityForEdition) {
    // prepare array to iterate over
    rarityForEdition = [];
    rarityWeights.forEach((rarityWeight) => {
      for (let i = rarityWeight.from; i <= rarityWeight.to; i++) {
        rarityForEdition.push(rarityWeight.value);
      }
    });
  }
  return rarityForEdition[editionSize - _editionCount];
};

const writeMetaData = (_data) => {
  fs.writeFileSync("./output/_metadata.json", _data);
};

// holds which dna has already been used during generation
let dnaListByRarity = {};
// holds metadata for all NFTs
let metadataList = [];
// image data collection
const imageDataArray = [];
let image_CID = "";
let meta_CID = "";
let ipfsArray = [];
// array of promises so that only if finished, will next promise be initiated
let promiseArray = [];

const saveToServer = async (_meta_hash, _image_hash) => {
  for (let i = 1; i < editionSize + 1; i++) {
    let id = i.toString();
    let paddedHex = (
      "0000000000000000000000000000000000000000000000000000000000000000" + id
    ).slice(-64);
    let url = `https://ipfs.moralis.io:2053/ipfs/${_meta_hash}/metadata/${paddedHex}.json`;
    let options = { json: true };
    request(url, options, (error, res, body) => {
      if (error) {
        return console.log(error);
      }

      if (!error && res.statusCode == 200) {
        // Save file reference to Moralis
        const FileDatabase = new Moralis.Object("Metadata");
        FileDatabase.set("edition", body.edition);
        FileDatabase.set("name", body.name);
        FileDatabase.set("dna", body.dna);
        FileDatabase.set("image", body.image);
        FileDatabase.set("attributes", body.attributes);
        FileDatabase.set("meta_hash", _meta_hash);
        FileDatabase.set("image_hash", _image_hash);
        FileDatabase.save();
      }
    });
  }
};

// upload metadata
const uploadMetadata = async (_cid) => {
  ipfsArray = [];
  promiseArray = [];

  for (let i = 1; i < editionSize + 1; i++) {
    let id = i.toString();
    let paddedHex = (
      "0000000000000000000000000000000000000000000000000000000000000000" + id
    ).slice(-64);
    let filename = i.toString() + ".json";

    let filetype = "base64";
    imageDataArray[
      i
    ].filePath = `https://ipfs.moralis.io:2053/ipfs/${_cid}/images/${paddedHex}.png`;
    //imageDataArray[i].image_file = res.data[i].content;

    // do something else here after firstFunction completes
    let nftMetadata = generateMetadata(
      imageDataArray[i].newDna,
      imageDataArray[i].editionCount,
      imageDataArray[i].attributesList,
      imageDataArray[i].filePath
    );
    metadataList.push(nftMetadata);

    const metaFile = new Moralis.File(filename, {
      base64: Buffer.from(
        JSON.stringify(metadataList.find((meta) => meta.edition == i))
      ).toString("base64"),
    });

    // save locally as file
    fs.writeFileSync(
      `./output/${filename}`,
      JSON.stringify(metadataList.find((meta) => meta.edition == i))
    );

    promiseArray.push(
      new Promise((res, rej) => {
        fs.readFile(`./output/${id}.json`, (err, data) => {
          if (err) rej();
          ipfsArray.push({
            path: `metadata/${paddedHex}.json`,
            content: data.toString("base64"),
          });
          res();
        });
      })
    );
  }
  Promise.all(promiseArray).then(() => {
    axios
      .post(api_url, ipfsArray, {
        headers: {
          "X-API-Key": xAPIKey,
          "content-type": "application/json",
          accept: "application/json",
        },
      })
      .then((res) => {
        meta_CID = res.data[0].path.split("/")[4];
        console.log("META FILE PATHS:", res.data);
        saveToServer(meta_CID, image_CID);
      })
      .catch((err) => {
        console.log(err);
      });
  });
};

// Create generative art by using the canvas api
const startCreating = async () => {
  console.log("##################");
  console.log("# Generative Art #");
  console.log("# - Generating your NFT collection");
  console.log("##################");
  console.log();

  // clear meta data from previous run
  writeMetaData("");

  // prepare dnaList object
  rarityWeights.forEach((rarityWeight) => {
    dnaListByRarity[rarityWeight.value] = [];
  });

  // create NFTs from startEditionFrom to editionSize
  let editionCount = startEditionFrom;

  while (editionCount <= editionSize) {
    console.log("-----------------");
    console.log("Mutating %d of %d", editionCount, editionSize);

    // upload to ipfs
    const saveFile = async () => {
      // get rarity from to config to create NFT as
      let rarity = getRarity(editionCount);
      console.log("- rarity: " + rarity);

      // calculate the NFT dna by getting a random part for each layer/feature
      // based on the ones available for the given rarity to use during generation
      let newDna = createDna(layers, rarity);
      while (!isDnaUnique(dnaListByRarity[rarity], newDna)) {
        // recalculate dna as this has been used before.
        console.log(
          "found duplicate DNA " + newDna.join("-") + ", recalculate..."
        );
        newDna = createDna(layers, rarity);
      }
      console.log("- dna: " + newDna.join("-"));

      // propagate information about required layer contained within config into a mapping object
      // = prepare for drawing
      let results = constructLayerToDna(newDna, layers, rarity);
      let loadedElements = [];

      // load all images to be used by canvas
      results.forEach((layer) => {
        loadedElements.push(loadLayerImg(layer));
      });

      let attributesList = [];

      await Promise.all(loadedElements).then((elementArray) => {
        // create empty image
        ctx.clearRect(0, 0, width, height);
        // draw a random background color
        drawBackground();
        // store information about each layer to add it as meta information
        attributesList = [];
        // draw each layer
        elementArray.forEach((element) => {
          drawElement(element);
          attributesList.push(getAttributeForElement(element));
        });
        // add an image signature as the edition count to the top left of the image
        signImage(`#${1}`);
        // write the image to the output directory
      });
      dnaListByRarity[rarity].push(newDna);

      const base64ImgData = canvas.toBuffer();
      const base64 = base64ImgData.toString("base64");

      let filename = editionCount.toString() + ".png";
      let filetype = "image/png";

      // save locally as file
      fs.writeFileSync(`./output/${filename}`, canvas.toBuffer(filetype));

      console.log(
        "Mutant " + editionCount.toString() + " a resident of Moralis"
      );

      imageDataArray[editionCount] = {
        editionCount: editionCount,
        newDna: newDna,
        attributesList: attributesList,
      };
    };

    const handleFinal = async () => {
      // write image  files
      const imageData = await saveFile();
    };

    await handleFinal();
    // iterate
    editionCount++;
  }

  ipfsArray = [];
  promiseArray = [];

  for (let i = 1; i < editionCount; i++) {
    let id = i.toString();
    let paddedHex = (
      "0000000000000000000000000000000000000000000000000000000000000000" + id
    ).slice(-64);

    promiseArray.push(
      new Promise((res, rej) => {
        fs.readFile(`./output/${id}.png`, (err, data) => {
          if (err) rej();
          ipfsArray.push({
            path: `images/${paddedHex}.png`,
            content: data.toString("base64"),
          });
          res();
        });
      })
    );
  }
  Promise.all(promiseArray).then(() => {
    axios
      .post(api_url, ipfsArray, {
        headers: {
          "X-API-Key": xAPIKey,
          "content-type": "application/json",
          accept: "application/json",
        },
      })
      .then((res) => {
        console.log("IMAGE FILE PATHS:", res.data);
        image_CID = res.data[0].path.split("/")[4];
        console.log("IMAGE CID:", image_CID);
        // pass folder CID to meta data
        uploadMetadata(image_CID);
      })
      .catch((err) => {
        console.log(err);
      });
  });

  writeMetaData(JSON.stringify(metadataList));
  console.log("#########################################");
  console.log("Welcome to Pixle");
  console.log("#########################################");
  console.log();
};

// Initiate code
startCreating();

I think that this error could happen usually if you don’t have the images in the right place for the script to read them

interesting ok how do i tell

you could try with fewer images, like 3 images maybe, I think that there is a constant in code that specifies the number of images

interesting would there be way to change that constant. because my specific project needs to generate a lot of people so having more combinations would be nice

i changes it so there is only a few pngs in each and still same error and even just put 1 png in and nothing

you could add more lines with console.log to identify where it stops

usually there was a problem with not finding a specific image or file on disk from where it tries to read it

ok i did now it getting caught on this line again thank you for your help still learning.

C:\Users\brans\Documents\2d game\Pixel people\index.js:145
Math.random() * layer.elementIdsForRarity[_rarity].length

i get that its can read it because its undefined but i don’t see how its not

here is where it is in the code

[quote="nosnarb1, post:6, topic:5895"]
// check if the given dna is contained within the given dnaList
// return true if it is, indicating that this dna is already in use and should be recalculated
const isDnaUnique = (_DnaList = [], _dna = []) => {
let foundDna = _DnaList.find((i) => i.join("") === _dna.join(""));
return foundDna == undefined ? true : false;
};

const getRandomRarity = (_rarityOptions) => {
let randomPercent = Math.random() * 100;
let percentCount = 0;

for (let i = 0; i <= _rarityOptions.length; i++) {
percentCount += _rarityOptions[i].percent;
if (percentCount >= randomPercent) {
console.log(`use random rarity ${_rarityOptions[i].id}`);
return _rarityOptions[i].id;
}
}
return _rarityOptions[0].id;
};

// create a dna based on the available layers for the given rarity
// use a random part for each layer
const createDna = (_layers, _rarity) => {
let randNum = [];
let _rarityWeight = rarityWeights.find((rw) => rw.value === _rarity);
_layers.forEach((layer) => {
let num = Math.floor(
Math.random() * layer.elementIdsForRarity[_rarity].length
);
if (_rarityWeight && _rarityWeight.layerPercent[layer.id]) {
// if there is a layerPercent defined, we want to identify which dna to actually use here (instead of only picking from the same rarity)
let _rarityForLayer = getRandomRarity(
_rarityWeight.layerPercent[layer.id]
);
num = Math.floor(
Math.random() * layer.elementIdsForRarity[_rarityForLayer].length
);
randNum.push(layer.elementIdsForRarity[_rarityForLayer][num]);
} else {
randNum.push(layer.elementIdsForRarity[_rarity][num]);
}
});
return randNum;
};
[/quote]

you can see here how to paste formatted code on forum: READ BEFORE POSTING - How to post code in the forum

1 Like

did that help? i tried to edit it

first code looks better now

what does the error say? what variables is undefined?

##################

Generative Art

- Generating your NFT collection

##################


Mutating 0 of 100

  • rarity: undefined
    C:\Users\brans\Documents\2d game\Pixel people\index.js:145
    Math.random() * layer.elementIdsForRarity[_rarity].length
    ^

TypeError: Cannot read properties of undefined (reading ‘length’)
at C:\Users\brans\Documents\2d game\Pixel people\index.js:145:58
at Array.forEach ()
at createDna (C:\Users\brans\Documents\2d game\Pixel people\index.js:143:11)
at saveFile (C:\Users\brans\Documents\2d game\Pixel people\index.js:328:20)
at handleFinal (C:\Users\brans\Documents\2d game\Pixel people\index.js:390:31)
at startCreating (C:\Users\brans\Documents\2d game\Pixel people\index.js:393:11)
at Object. (C:\Users\brans\Documents\2d game\Pixel people\index.js:453:1)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions…js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47

this would mean that this is undefined

right so then how do i define it i guess i thought i did here

const getRandomRarity = (_rarityOptions) => {
  let randomPercent = Math.random() * 100;
  let percentCount = 0

that seems to be an array, dat doesn’t have data for a particular _rarity