Generate art and metadata
mainTo run the generation engine, use npm run build or node index.js.
Output locations:
- Images:
build/images - Metadata JSON:
build/json - Collection summary:
build/json/_metadata.json
npm run build
# or
node index.jsrepository·main·Indexed 27 days ago
https://github.com/hashlips/hashlips_art_engineA Node.js-based tool (v1.1.1) for creating generative art collections. It uses the Canvas API to layer assets and automatically generate unique images and corresponding metadata JSON files. Features include rarity weight assignment, custom blending modes, pixelation, GIF export, and specific metadata configurations for networks like Solana.
To run the generation engine, use npm run build or node index.js.
Output locations:
build/imagesbuild/jsonbuild/json/_metadata.jsonnpm run build
# or
node index.jsOrganize your assets into folders within the /layers/ directory. To assign rarity, append a weight to the filename using a delimiter (default is #), for example: example element#70.png.
You can customize the delimiter by changing the rarityDelimiter variable in src/config.js.
To use the HashLips Art Engine, ensure you have Node.js (v10.18.0) installed. You can install the project by cloning the repository and using either yarn or npm to install dependencies.
git clone https://github.com/HashLips/hashlips_art_engine.git
# If using yarn
yarn install
# Or if using npm
npm installTo export GIFs based on your layers, set export: true in the gif object within src/config.js. You can configure repeat, quality, and delay (in ms).
Note: repeat: -1 creates a single frame render, while repeat: 0 loops the GIF infinitely.
const gif = {
export: true,
repeat: 0,
quality: 100,
delay: 500,
};To include custom key-value pairs in every metadata file, define an extraMetadata object in src/config.js.
const extraMetadata = {
creator: "Daniel Eugene Botha",
};In src/config.js, configure the layerConfigurations array. Each object defines a set of layers and the total number of artworks to generate using growEditionSizeTo. The layersOrder array specifies the order of layers from back to front. The name property must match the folder name in the /layers/ directory.
const layerConfigurations = [
{
growEditionSizeTo: 100,
layersOrder: [
{ name: "Background" },
{ name: "Head" },
{ name: "Mouth" },
{ name: "Eyes" },
{ name: "Eyeswear" },
{ name: "Headwear" },
],
},
];You can enhance layers by adding an options object to the layer definition in layersOrder. Supported options include:
blend: Sets the canvas blending mode using the MODE object.opacity: Sets the layer transparency (e.g., 0.7).bypassDNA: If true, this layer is included in the image but ignored during the DNA uniqueness check.displayName: Overrides the default attribute name in the metadata.const layerConfigurations = [
{
growEditionSizeTo: 5,
layersOrder: [
{ name: "Background" , options: { bypassDNA: true } },
{ name: "Eyeball" },
{
name: "Eye color",
options: {
blend: MODE.destinationIn,
opacity: 0.2,
displayName: "Awesome Eye Color",
},
},
{ name: "Iris" },
{ name: "Shine" },
{ name: "Bottom lid", options: { blend: MODE.overlay, opacity: 0.7 } },
{ name: "Top lid" },
],
},
];index.js file serves as the primary entrypoint to initiate the art generation process. When executed, it automatically runs buildSetup() to prepare the environment and startCreating() to begin the generation of the art collection based on your configuration. To run the engine, execute this file using Node.js from your project root.The config.js file is the primary configuration surface for the HashLips Art Engine. It controls metadata, layer composition, image formatting, and output settings.
Key configuration sections include:
namePrefix, description, and baseUri (e.g., ipfs://...) for the collection.NETWORK.eth).solanaMetadata with symbol, seller_fee_basis_points (where 1000 = 10%), external_url, and creators array.layerConfigurations to set the growEditionSizeTo target and the layersOrder (the order in which layers are stacked).format object (width, height, smoothing).gif object (export, repeat, quality, delay).text object (color, size, align, family, etc.).background object (generate, brightness, static, default).rarityDelimiter (default #) and uniqueDnaTorrance (the range for DNA generation).const layerConfigurations = [
{
growEditionSizeTo: 5,
layersOrder: [
{ name: "Background" },
{ name: "Eyeball" },
{ name: "Eye color" },
{ name: "Iris" },
{ name: "Shine" },
{ name: "Bottom lid" },
{ name: "Top lid" },
],
},
];
const format = {
width: 512,
height: 512,
smoothing: false,
};When generating for Solana, use the solanaMetadata object to define on-chain attributes.
symbol: The collection symbol.seller_fee_basis_points: The percentage taken from secondary market sales. Note that this is in basis points (e.g., 1000 equals 10%).external_url: A link to the project website or social media.creators: An array of objects containing the address and the share (percentage) for each creator.const solanaMetadata = {
symbol: "YC",
seller_fee_basis_points: 1000, // 1000 = 10%
external_url: "https://www.youtube.com/c/hashlipsnft",
creators: [
{
address: "7fXNuer5sbZtaTEPhtJ5g5gNtuyRoKkvxdjEjEnPN4mC",
share: 100,
},
],
};Use the layerConfigurations array to define how your collection is built.
growEditionSizeTo: The total number of unique items to generate.layersOrder: An array of objects specifying the name of each layer. Layers are stacked in the order they appear in this array (the first item is the bottom-most layer).Note: If you are using Solana, the collection index starts from 0 automatically.
const layerConfigurations = [
{
growEditionSizeTo: 5,
layersOrder: [
{ name: "Background" },
{ name: "Eyeball" },
{ name: "Eye color" },
{ name: "Iris" },
{ name: "Shine" },
{ name: "Bottom lid" },
{ name: "Top lid" },
],
},
];The MODE object contains the following valid blending mode strings for the blend option:
const MODE = {
sourceOver: "source-over",
sourceIn: "source-in",
sourceOut: "source-out",
sourceAtop: "source-out",
destinationOver: "destination-over",
destinationIn: "destination-in",
destinationOut: "destination-out",
destinationAtop: "destination-atop",
lighter: "lighter",
copy: "copy",
xor: "xor",
multiply: "multiply",
screen: "screen",
overlay: "overlay",
darken: "darken",
lighten: "lighten",
colorDodge: "color-dodge",
colorBurn: "color-burn",
hardLight: "hard-light",
softLight: "soft-light",
difference: "difference",
exclusion: "exclusion",
hue: "hue",
saturation: "saturation",
color: "color",
luminosity: "luminosity",
};