diff --git a/color datagen/base_with_mask.js b/color datagen/base_with_mask.js
new file mode 100644
index 000000000..e3be0dc5b
--- /dev/null
+++ b/color datagen/base_with_mask.js	
@@ -0,0 +1,68 @@
+
+const args = process.argv.slice(2)
+
+if (args.length < 2) {
+	console.error('Usage: node base_with_mask.js <base_name> <mask_name> [subfolder]\n')
+	console.error('If subfolder specified, resulting file name will contain only color name\n')
+	console.error('Subfolder is relative to base texture path\n')
+	process.exit(2)
+}
+
+const fs = require('fs')
+const {colorsWithWhite, rootFolder, splitName, getSize} = require('./include.js')
+const child_process = require('child_process');
+
+(async function() {
+	const baseTexture = args[0]
+	const maskTexture = args[1]
+	const subfolder = args[2] ?? ''
+
+	const fBase = `${rootFolder}${baseTexture}.png`
+	const fMask = `${rootFolder}${maskTexture}.png`
+
+	if (!fs.existsSync(fBase)) {
+		process.stderr.write(`${fBase} does not exist\n`)
+		process.exit(1)
+	}
+
+	if (!fs.existsSync(fMask)) {
+		process.stderr.write(`${fMask} does not exist\n`)
+		process.exit(1)
+	}
+
+	const [fileName, _, fullBaseFolder] = splitName(baseTexture)
+	const bSize = (await getSize(fBase))[2]
+	const mSize = (await getSize(fMask))[2]
+
+	if (bSize != mSize) {
+		process.stderr.write(`${fBase} has size of ${bSize}, ${fMask} has size of ${mSize}!\n`)
+		process.exit(3)
+	}
+
+	for (const [name, _, xc] of colorsWithWhite) {
+		const outputFilename = subfolder === '' ? `${fullBaseFolder}/${fileName}_${name}.png` : `${fullBaseFolder}/${subfolder}/${name}.png`
+
+		const magick = child_process.spawn('magick', [
+			'convert',
+
+			fBase,
+
+			'(',
+				fMask,
+				'-size', bSize,
+				xc,
+				'-channel', 'rgb',
+				'-compose', 'Multiply',
+				'-composite',
+			')',
+
+			'-compose', 'Over',
+			'-composite',
+
+			outputFilename])
+
+		magick.stdout.pipe(process.stdout)
+		magick.stderr.pipe(process.stderr)
+	}
+})();
+
diff --git a/color datagen/computer_block.sh b/color datagen/computer_block.sh
new file mode 100644
index 000000000..0c01736c0
--- /dev/null
+++ b/color datagen/computer_block.sh	
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+node ./base_with_mask.js block/decorative/computer_base block/decorative/computer_base_mask computer_base
+node ./base_with_mask.js block/decorative/computer_screen block/decorative/computer_screen_mask computer_screen
diff --git a/color datagen/include.js b/color datagen/include.js
new file mode 100644
index 000000000..8d2f3b625
--- /dev/null
+++ b/color datagen/include.js	
@@ -0,0 +1,76 @@
+
+const colors = [
+	['orange', [245, 116, 16]],
+	['magenta', [186, 63, 175]],
+	['light_blue', [59, 180, 219]],
+	['yellow', [252, 199, 36]],
+	['lime', [111, 187, 24]],
+	['pink', [243, 139, 170]],
+	['gray', [62, 66, 70]],
+	['light_gray', [140, 140, 131]],
+	['cyan', [22, 134, 145]],
+	['purple', [116, 38, 169]],
+	['blue', [51, 53, 155]],
+	['brown', [114, 71, 40]],
+	['green', [84, 109, 28]],
+	['red', [156, 37, 34]],
+	['black', [31, 31, 35]],
+]
+
+const white = ['white', [235, 235, 235]]
+const colorsWithWhite = [...colors]
+colorsWithWhite.push(white)
+
+function addRgbString(values) {
+	for (const row of values) {
+		const rgb = row[1]
+		row.push(`xc:rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`)
+	}
+}
+
+addRgbString(colors)
+addRgbString(colorsWithWhite)
+
+const rootFolder = '../src/main/resources/assets/overdrive_that_matters/textures/'
+const child_process = require('child_process')
+
+process.stdout.setMaxListeners(900)
+process.stderr.setMaxListeners(900)
+
+async function getSize(path) {
+	const identify = child_process.spawn('magick', [
+		'identify',
+		path,
+	])
+
+	identify.stderr.pipe(process.stderr)
+
+	const chunks = []
+	identify.stdout.on('data', (a) => chunks.push(a))
+
+	await new Promise((resolve) => {
+		identify.on('close', () => resolve())
+	})
+
+	const chunk = chunks[0].toString('utf-8')
+	const size = chunk.match(/PNG ([0-9]+)x([0-9]+)/)
+	const width = parseInt(size[1])
+	const height = parseInt(size[2])
+
+	return [width, height, `${width}x${height}`]
+}
+
+function splitName(name) {
+	const splitted = name.split('/')
+	const fileName = splitted.pop()
+	const baseFolder = splitted.join('/')
+	const fullBaseFolder = `${rootFolder}${baseFolder}`
+
+	return [fileName, baseFolder, fullBaseFolder, fileName.indexOf('_white') == -1 ? colorsWithWhite : colors]
+}
+
+exports.colors = colors
+exports.colorsWithWhite = colorsWithWhite
+exports.rootFolder = rootFolder
+exports.splitName = splitName
+exports.getSize = getSize