Added config file and cleanup

This commit is contained in:
Marco van Dijk 2022-10-09 22:37:03 +02:00
parent 8717eefd21
commit 603aa7c5b2
9 changed files with 123 additions and 1865 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@ build/
*.log
notes.txt
output
converted
converted
package-lock.json

48
config/default.json Normal file
View File

@ -0,0 +1,48 @@
{
"control": {
"iterations": 500,
"threads": 1,
"minId": 1,
"maxId": 999998,
"path": "./output/"
},
"generate": {
"helmet": {
"classic": 0.2,
"racer": 0.1,
"punk": 0.1,
"knight": 0.2,
"geek": 0.2
},
"patch": {
"livepeer": 0.2,
"nimbus": 0.1,
"teku": 0.1,
"lighthouse": 0.1,
"prysm": 0.2,
"rocketpool": 0.3
},
"backpack": {
"yes": 0.9,
"no": 0.1
},
"panel": {
"yes": 0.9,
"no": 0.1
},
"background": {
"planets": 0.2,
"system": 0.2,
"playful": 0.1,
"moon": 0.05,
"galaxy": 0.2,
"chip": 0.05
},
"backgroundComplexity": {
"complex": 0.1,
"med": 0.15,
"low": 0.25,
"basic": 0.50
}
}
}

View File

@ -1,8 +1,9 @@
import os
import cairosvg
from pathlib import Path
# Create path
Path("./converted/").mkdir(parents=True, exist_ok=True)
# Convert all .svg's in the ./output folder to ./converted/ as .png
for file in os.listdir('./output'):
name = file.split('.svg')[0]
print('Converting ' + './output/' + name + '.svg' + ' -> ./converted/' + name + '.png')

View File

@ -1,11 +1,26 @@
const config = require('config');
const iterations = config.get('control.iterations');
const threads = config.get('control.threads');
const minId = config.get('control.minId');
const maxId = config.get('control.maxId');
const basePath = config.get('control.path');
const { generateRocketeer } = require("./nft-media/rocketeer");
(async () => {
try {
while (true) {
const id = Math.floor(Math.random() * (999998) + 1)
// Sanity check on config variables
let todo = iterations;
if (isNaN(todo)){
console.log("Cannot create `" + todo + "' amount Captain Chads");
return;
}else if (todo < 1){todo = 1;}
if (minId >= maxId){return;}
// Generate new Captain Chad's
while (todo) {
const id = Math.floor(Math.random() * (maxId) + minId)
console.log("Generating Cpn Chad " + id);
console.log(await generateRocketeer(id));
console.log(await generateRocketeer(id, basePath));
todo--;
}
process.exit(0);
} catch (err) {

View File

@ -1,16 +1,5 @@
// ///////////////////////////////
// Helper functions
// ///////////////////////////////
exports.dev = !!process.env.development;
const log = (...messages) => {
if (process.env.development) console.log(...messages);
};
exports.log = log;
// Wait in async
const wait = (timeInMs) =>
new Promise((resolve) => setTimeout(resolve), timeInMs);
exports.wait = wait;
const config = require("config");
const parameters = config.get("generate");
// Pick random item from an array
const pickRandomArrayEntry = (array) =>
@ -50,91 +39,61 @@ exports.pickRandomAttributes = (attributes) => {
}));
};
const nameColor = require("color-namer");
const Color = require("color");
exports.getColorName = (rgb) => {
try {
return nameColor(rgb).basic[0].name;
} catch (e) {
return rgb;
}
};
exports.getRgbArrayFromColorName = (name) => {
const { hex } = nameColor(name).basic[0];
const color = Color(hex);
return color.rgb().array();
};
// ///////////////////////////////
// Attribute sources
// ///////////////////////////////
// Define all Captain Chad attributes
exports.globalAttributes = [
{
trait_type: "helmet",
values: [
{ value: "classic", probability: 0.2 },
{ value: "racer", probability: 0.1 },
{ value: "punk", probability: 0.1 },
{ value: "knight", probability: 0.2 },
{ value: "geek", probability: 0.2 },
{ value: "classic", probability: parameters.helmet.classic },
{ value: "racer", probability: parameters.helmet.racer },
{ value: "punk", probability: parameters.helmet.punk },
{ value: "knight", probability: parameters.helmet.knight },
{ value: "geek", probability: parameters.helmet.geek },
],
},
{
trait_type: "patch",
values: [
{ value: "livepeer", probability: 0.2 },
{ value: "nimbus", probability: 0.1 },
{ value: "teku", probability: 0.1 },
{ value: "lighthouse", probability: 0.1 },
{ value: "prysm", probability: 0.2 },
{ value: "rocketpool", probability: 0.3 },
{ value: "livepeer", probability: parameters.patch.livepeer },
{ value: "nimbus", probability: parameters.patch.livepeer },
{ value: "teku", probability: parameters.patch.livepeer },
{ value: "lighthouse", probability: parameters.patch.livepeer },
{ value: "prysm", probability: parameters.patch.livepeer },
{ value: "rocketpool", probability: parameters.patch.livepeer },
],
},
{
trait_type: "backpack",
values: [
{ value: "yes", probability: 0.9 },
{ value: "no", probability: 0.1 },
{ value: "yes", probability: parameters.backpack.yes },
{ value: "no", probability: parameters.backpack.no },
],
},
{
trait_type: "panel",
values: [
{ value: "yes", probability: 0.9 },
{ value: "no", probability: 0.1 },
{ value: "yes", probability: parameters.panel.yes },
{ value: "no", probability: parameters.panel.no },
],
},
{
trait_type: "background",
values: [
{ value: "planets", probability: 0.2 },
{ value: "system", probability: 0.2 },
{ value: "playful", probability: 0.1 },
{ value: "moon", probability: 0.05 },
{ value: "galaxy", probability: 0.2 },
{ value: "chip", probability: 0.05 },
{ value: "planets", probability: parameters.background.planets },
{ value: "system", probability: parameters.background.system },
{ value: "playful", probability: parameters.background.playful },
{ value: "moon", probability: parameters.background.moon },
{ value: "galaxy", probability: parameters.background.galaxy },
{ value: "chip", probability: parameters.background.chip },
],
},
{
trait_type: "background complexity",
values: [
{ value: 1, probability: 0.05 },
{ value: 2, probability: 0.1 },
{ value: 3, probability: 0.1 },
{ value: 4, probability: 0.75 },
{ value: 1, probability: parameters.backgroundComplexity.complex },
{ value: 2, probability: parameters.backgroundComplexity.med },
{ value: 3, probability: parameters.backgroundComplexity.low },
{ value: 4, probability: parameters.backgroundComplexity.basic },
],
},
];
exports.heavenlyBodies = [
"Mercury",
"Venus",
"Earth",
"Mars",
"Jupiter",
"Saturn",
"Uranus",
"Neptune",
"Pluto",
"the Moon",
"the Sun",
];

View File

@ -1,44 +1,19 @@
const name = require("random-name");
const {
pickRandomArrayEntry,
pickRandomAttributes,
randomNumberBetween,
globalAttributes,
heavenlyBodies,
getColorName,
globalAttributes
} = require("../modules/helpers");
const svgFromAttributes = require("./svg-generator");
// ///////////////////////////////
// Rocketeer generator
// ///////////////////////////////
async function generateRocketeer(id) {
// The base object of a new Rocketeer
// Generates a random Chad names as basePath/id.svg
async function generateRocketeer(id, basePath) {
const rocketeer = {
name: `${name.first()} ${name.middle()} ${name.last()} of ${
id % 42 == 0 ? "the Towel" : pickRandomArrayEntry(heavenlyBodies)
}`,
description: "",
image: ``,
attributes: [],
};
// Generate randomized attributes
// Pick random attributes based on configured probabilities
rocketeer.attributes = pickRandomAttributes(globalAttributes);
// Set birthday
rocketeer.attributes.push({
display_type: "date",
trait_type: "birthday",
value: Math.floor(Date.now() / 1000),
});
// Create description
rocketeer.description = `${rocketeer.name} is a proud member of the ${
rocketeer.attributes.find(({ trait_type }) => trait_type == "patch").value
} guild.`;
// Generate color attributes
// Randomize colours
rocketeer.attributes.push({
trait_type: "outfit color",
value: `rgb( ${randomNumberBetween(0, 255)}, ${randomNumberBetween(
@ -67,27 +42,10 @@ async function generateRocketeer(id) {
255
)}, ${randomNumberBetween(0, 255)} )`,
});
// Generate, compile and upload image
const { NODE_ENV: mode } = process.env;
let path = "./output/" + id;
// if (mode == "production") {
// path = "/var/www/avatars/" + id;
// } else {
// path = "./output/" + id;
// }
// Generate SVG
let path = basePath + id;
rocketeer.image = await svgFromAttributes(rocketeer.attributes, path);
// Namify the attributes
rocketeer.attributes = rocketeer.attributes.map((attribute) => {
if (!attribute.trait_type.includes("color")) return attribute;
return {
...attribute,
value: getColorName(attribute.value),
};
});
return rocketeer.name + ": `" + rocketeer.description + "' @ " + rocketeer.image;
return "@" + rocketeer.image;
}
module.exports = {

View File

@ -9,9 +9,7 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
if (!attributes.length)
throw new Error("svgFromAttributes missing attributes");
console.log("Checking attributes");
// Get properties
console.log("Getting attributes...");
const { value: primary_color } = attributes.find(
({ trait_type }) => trait_type == "outfit color"
);
@ -43,20 +41,15 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
({ trait_type }) => trait_type == "background complexity"
);
console.log("Reading master file");
console.log("Reading master file...");
// Generate DOM to work with
const svgString = await fs.readFile(masterPath, { encoding: "utf8" });
const {
window: { document },
} = new JSDOM(svgString);
// ///////////////////////////////
// Attribute selection
// ///////////////////////////////
console.log("Removing unused attributes from master");
// Remove obsolete patches
// Remove unused patches
const obsoletePatches = [
"livepeer",
"nimbus",
@ -71,7 +64,7 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
else console.log(`Could not find #${obsoletePatches[i]}`);
}
// Remove obsolete hemets
// Remove unused helmets
const obsoleteHelmets = ["classic", "racer", "punk", "knight", "geek"].filter(
(p) => p !== helmet
);
@ -88,21 +81,21 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
}
}
// Remove panel if need be
// Remove unused panels
if (panel === "no") {
const element = document.querySelector(`#panel`);
if (element) element.remove();
else console.log(`Could not find #panel`);
}
// Remove backpack if need be
// Remove unused backpacks
if (backpack === "no") {
const element = document.querySelector(`#backpack`);
if (element) element.remove();
else console.log("Could not find #backpack");
}
// Remove obsolete backgrounds
// Remove unused backgrounds
const obsoleteBackgrounds = [
"planets",
"system",
@ -117,11 +110,7 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
else console.log(`Could not find #${obsoleteBackgrounds[i]}`);
}
// ///////////////////////////////
// Background customisation
// ///////////////////////////////
// In playful, keeping things is basic, removing them is cool
// With a playful background: more rarity->less complexity
if (background === "playful") {
const toRemove = background_complexity;
for (let i = 1; i <= toRemove; i++) {
@ -130,8 +119,7 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
else console.log(`Could not find #playful-element-${5 - i}`);
}
} else {
// In others, keeping is cool, and removing is less cool
// so higher rarity means less looping
// With a playful background: more rarity->more complexity
const toRemove = 4 - background_complexity;
for (let i = 1; i <= toRemove; i++) {
const element = document.querySelector(`#${background}-element-${5 - i}`);
@ -140,9 +128,7 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
}
}
// ///////////////////////////////
// Color substitutions
// ///////////////////////////////
// Substitute master colours for generated ones
console.log("Substituting colours from master");
const defaultPrimary = /rgb\( ?252 ?, ?186 ?, ?157 ?\)/gi;
const defaultVisor = /rgb\( ?71 ?, ?22 ?, ?127 ?\)/gi;
@ -159,18 +145,19 @@ module.exports = async function svgFromAttributes(attributes = [], path = "") {
replace(defaultVisor, visor_color);
replace(defaultBackpack, backpack_color);
console.log("Baking SVG now...");
console.log("Generating SVG...");
const bakedSvg = [
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>`,
`<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">`,
document.querySelector("svg").outerHTML,
].join("");
// Write SVG to file
const dir = path.split('/').slice(0, -1).join('/');
await fs.mkdir(dir, { recursive: true });
console.log("Writing to `" + path + ".svg`...");
await fs.writeFile(`${path}.svg`, bakedSvg);
// Return public url
return "Paths: '" + `${path}.svg` + "'";
// Return output location
return `${path}.svg`;
};

1709
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "RandomChad",
"version": "0.1.0",
"version": "0.1.1",
"description": "",
"main": "index.js",
"module": "index.js",
@ -12,10 +12,8 @@
"author": "",
"license": "",
"dependencies": {
"color": "^4.2.3",
"color-namer": "^1.4.0",
"jsdom": "^18.1.1",
"random-name": "^0.1.2"
"config": "^3.3.8",
"jsdom": "^18.1.1"
},
"devDependencies": {
"nodemon": "^2.0.20"