Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
True Fur | Violet CLM | Mutator | 9.5 |
<!doctype html>
<html>
<head>
<meta charset="windows-1252">
<title>Fur color designer for TrueFur.mut</title>
<style>
main {
max-width: 640px;
margin: 0 auto;
}
#preview {
margin-top: 0.5em;
padding-top: calc(100% * 103/120);
background-size: cover;
image-rendering: pixelated;
}
button {
width: 20%;
display: inline-block;
}
ul {
list-style: none;
padding-left: 0;
}
#gradients > li {
width: 50%;
display: inline-block;
}
ul.gradient {
width: 100%;
}
ul.gradient > li {
display: inline-block;
width: 11%;
height: 0;
padding-top: calc(11% - 6px);
position: relative;
box-sizing: border-box;
}
ul.gradient > li + li {
border: 3px inset;
position: relative;
}
li.enabled {
border-style: outset !important;
}
ul.gradient > li + li:not(.enabled):after {
content: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAANCAMAAACn6Q83AAAAB3RJTUUH5wgeECEaKvilHgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAAAbUExURZPC6AsHB1dLP3drV5uLc7uvk9vPr//z0y8jHwIMCFsAAAABdFJOUwBA5thmAAAAS0lEQVR42jWOCwoAQQhC0+xz/xPvVKwgPAQtMzM82QqRpWWoFOnDyCAvRqm5KVreYxhc8vHg60flYiWZ9afcNVBBD3EmOCXeOdwTH2dbAXTdwzryAAAAAElFTkSuQmCC");
position: absolute;
bottom: -3px;
right: -3px;
mix-blend-mode: luminosity;
}
li.enabled input[type=color] {
opacity: 0;
visibility: visible;
cursor: pointer;
}
select {
position: absolute;
top: -3px; bottom: 3px;
width: 100%;
}
input[type=color] {
position: absolute;
width: 100%;
top: 0; left: 0; bottom: 0; right: 0;
box-sizing: border-box;
visibility: hidden;
}
input[type=file] {
display: none;
}
#buttons {
position: sticky;
top: 0;
}
</style>
</head>
<body
><main
><div id="buttons"
><input type="file" id="hiddenload" accept=".asdat"
><button id="butload">Load</button
><button class="butsave">Save Player 1</button
><button class="butsave">Save Player 2</button
><button class="butsave">Save Player 3</button
><button class="butsave">Save Player 4</button
></div
><div id="preview"></div
><ul id="gradients"
></ul
></main>
<script>
const FILEVERSION = 0;
window.addEventListener('load', function() {
const CanonGradients = {
Green: [199,255,0, 147,223,0, 107,191,0, 71,163,0, 43,131,0, 19,103,0, 7,55,0, 0,11,0],
Red: [255,0,0, 227,0,0, 199,0,0, 171,0,0, 143,0,0, 115,0,0, 63,0,0, 11,0,0],
Blue: [187,227,255, 123,199,255, 59,171,255, 0,139,255, 0,107,203, 0,79,151, 0,47,79, 0,7,11],
Orange: [255,255,0, 255,199,0, 255,147,0, 255,95,0, 203,55,0, 155,27,0, 83,7,0, 11,0,0],
Pink: [251,139,183, 247,91,151, 243,43,123, 239,0,99, 191,0,75, 147,0,55, 99,0,35, 55,0,19],
Yellow: [255,255,0, 240,235,0, 230,210,0, 219,195,0, 187,147,0, 155,107,0, 83,55,0, 11,7,0],
Brown: [255,243,211, 219,207,175, 187,175,147, 155,139,115, 119,107,87, 87,75,63, 47,35,31, 11,7,7],
Silver: [211,231,255, 171,195,219, 139,159,187, 107,127,155, 75,95,119, 51,63,87, 27,31,47, 7,7,11],
Greenblue: [0,255,163, 0,227,127, 7,199,95, 7,171,67, 11,143,47, 11,119,31, 0,63,7, 0,11,0],
Purple: [231,119,255, 231,71,239, 223,31,207, 207,0,163, 163,0,127, 119,0,91, 63,0,43, 11,0,7],
AltRed: [255,0,0, 219,0,19, 183,0,35, 147,0,39, 115,0,43, 79,0,35, 43,0,23, 11,0,7],
AltYellow: [255,255,0, 231,231,0, 219,219,0, 199,199,0, 155,155,0, 115,115,0, 75,75,0, 35,35,0],
AltGreenblue: [0,255,211, 0,227,179, 0,199,151, 0,171,127, 0,135,103, 0,103,75, 0,55,39, 0,11,7],
AltPurple: [255,99,255, 215,67,223, 179,43,195, 147,23,167, 111,7,139, 83,0,111, 47,0,63, 11,0,15],
AltPurple2: [219,127,255, 203,63,255, 187,0,255, 163,0,211, 139,0,171, 107,0,127, 51,0,67, 7,0,11],
JustinYellow: [255,255,4, 200,200,0, 155,156,0, 130,130,0, 116,116,0, 63,62,0, 47,35,0, 11,11,0],
JustinBlue: [0,138,255, 0,107,204, 0,93,177, 0,79,151, 0,47,98, 0,39,71, 0,23,47, 7,6,12],
JustinBlue2: [7,251,248, 6,203,248, 0,152,239, 0,101,231, 0,48,224, 4,0,224, 0,23,148, 0,43,72],
JustinPink: [228,179,255, 219,126,255, 247,112,163, 241,51,131, 240,0,100, 199,0,0, 143,0,0, 63,0,0],
JustinOrange: [255,199,4, 254,148,4, 254,95,4, 255,2,0, 239,0,100, 191,0,76, 146,0,56, 79,0,11],
JustinBlack: [109,108,109, 63,63,62, 33,32,33, 16,16,16, 8,9,8, 7,7,7, 3,4,4, 2,3,3],
JustinMagenta: [236,64,127, 216,30,127, 193,0,127, 166,0,104, 141,0,85, 111,0,63, 56,0,33, 9,3,5],
MouseguyDeadscrap: [204,102,81, 178,63,55, 153,30,30, 127,12,22, 102,0,17, 76,0,19, 51,0,16, 25,0,10]
};
let recolor = new Uint8Array(3 * (10 * 8 + 1));
recolor[0] = recolor[1] = recolor[2] = 255; //white for Lori's eyes
let gradients = document.getElementById("gradients");
let addText = "<li><ul class='gradient'><li><select>";
addText += "<option>Fill</option>";
addText += "<option>1-color Gradient</option>";
addText += "<option>2-color Gradient</option>";
addText += "<option>3-color Gradient</option>";
addText += "<option>Fully Custom</option>";
for (let key in CanonGradients)
addText += "<option>" + key + "</option>";
addText += "</select></li>";
for (let c = 0; c < 8; ++c)
addText += "<li><input type='color' /></li>";
addText += "</ul></li>";
for (let i = 0; i < 10; ++i)
gradients.insertAdjacentHTML("beforeend", addText);
let selects = document.getElementsByTagName("select");
let rows = document.getElementsByClassName("gradient");
for (let i = 0; i < 10; ++i) {
let select = selects[i];
let children = rows[i].childNodes;
select.addEventListener("change", function(){
let enableds;
switch (this.selectedIndex) {
case 0: //fill
enableds = [true, false, false, false, false, false, false, false];
break;
case 1: //1-color gradient
enableds = [false, false, true, false, false, false, false, false];
break;
case 2: //2-color gradient
enableds = [false, false, true, false, false, true, false, false];
break;
case 3: //3-color gradient
enableds = [true, false, true, false, false, true, false, false];
break;
case 4: //fully custom
enableds = [true, true, true, true, true, true, true, true];
break;
default:
enableds = [false, false, false, false, false, false, false, false];
let channels = CanonGradients[this.value];
for (let c = 0; c < 8; ++c) {
const recolorOffset = (1 + c + i * 8) * 3;
for (let cc = 0; cc < 3; ++cc)
recolor[recolorOffset + cc] = channels[c * 3 + cc];
}
break;
}
for (let c = 0; c < 8; ++c)
children[c + 1].className = enableds[c] ? "enabled" : "";
generateGradient(i);
});
function generateGradient(gradientID) {
let recolorOffset = (1 + gradientID * 8) * 3;
const gradientType = selects[gradientID].selectedIndex;
if (gradientType == 0) { //fill
for (let c = 0; c < 24; c += 3)
for (let cc = 0; cc < 3; ++cc)
recolor[recolorOffset + c + cc] = recolor[recolorOffset + cc];
} else if (gradientType < 4) { //partially defined gradient
function multiplyColor(oldOffset, newOffset, factor) {
oldOffset *= 3;
newOffset *= 3;
for (let cc = 0; cc < 3; ++cc) {
let intensity = recolor[recolorOffset + oldOffset + cc];
intensity = intensity * factor | 0;
if (intensity) {
if (intensity > 255)
intensity = 255;
else
intensity |= 3;
}
recolor[recolorOffset + newOffset + cc] = intensity;
}
}
if (gradientType == 3) { //3-color gradient, defines top color
for (let cc = 0; cc < 3; ++cc)
recolor[recolorOffset + 3 + cc] = (recolor[recolorOffset + 0 + cc] + recolor[recolorOffset + 6 + cc]) / 2 | 3; //color 1 is average of colors 0 and 2
} else { //generate top color
multiplyColor(2, 1, 1.2);
multiplyColor(2, 0, 1.5);
}
if (gradientType == 1) { //1-color gradient, need to derive a lot of middle colors
multiplyColor(2, 3, 0.8);
multiplyColor(2, 4, 0.6);
multiplyColor(2, 5, 0.4);
} else { //colors 3 and 4 are averages of 2 and 5
for (let cc = 0; cc < 3; ++cc) {
const startColor = recolor[recolorOffset + 6 + cc];
const step = (recolor[recolorOffset + 15 + cc] - startColor) / 3;
recolor[recolorOffset + 9 + cc] = (startColor + step) | 3;
recolor[recolorOffset + 12 + cc] = (startColor + step * 2) | 3;
}
}
multiplyColor(5, 6, 0.525);
multiplyColor(5, 7, 0.125);
}
for (let c = 0; c < 8; ++c) {
const rgbstring = recolor[recolorOffset] + "," + recolor[recolorOffset + 1] + "," + recolor[recolorOffset + 2];
children[c + 1].title = rgbstring;
children[c + 1].style.background = children[c + 1].style.borderColor = "rgb(" + rgbstring + ")";
children[c + 1].childNodes[0].value = "#" + recolor[recolorOffset].toString(16).padStart(2, '0') + recolor[recolorOffset + 1].toString(16).padStart(2, '0') + recolor[recolorOffset + 2].toString(16).padStart(2, '0');
recolorOffset += 3;
}
}
select.selectedIndex = i + 5;
select.dispatchEvent(new Event("change"));
for (let cell = 1; cell < 9; ++cell) {
let li = children[cell];
li.childNodes[0].addEventListener("input", function() {
const r = parseInt(this.value.substr(1,2), 16);
const g = parseInt(this.value.substr(3,2), 16);
const b = parseInt(this.value.substr(5,2), 16);
const recolorOffset = (1 + i * 8 + (cell - 1)) * 3;
recolor[recolorOffset + 0] = r;
recolor[recolorOffset + 1] = g;
recolor[recolorOffset + 2] = b;
generateGradient(i);
draw();
});
}
}
const grayscale = new Image();
grayscale.src = "data:image/png;base64,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";
function draw() {
const cnvs = document.createElement("canvas");
const w = grayscale.width, h=grayscale.height;
if (!h) {
return setTimeout(draw, 500);
}
cnvs.width = w; cnvs.height = h;
const ctx = cnvs.getContext("2d");
ctx.drawImage(grayscale, 0,0);
const imgdata = ctx.getImageData(0,0,w,h);
const rgba = imgdata.data;
for (let px=0,ct=w*h*4; px<ct; px+=4) {
const brightness = rgba[px];
if (brightness) //not color 0, which is transparent
for (let ch = 0; ch < 3; ++ch) {
const recolorOffset = (brightness - 15) * 3;
rgba[px+ch] = recolor[recolorOffset + ch];
}
}
ctx.putImageData(imgdata,0,0);
document.getElementById("preview").style.backgroundImage = "url('" + cnvs.toDataURL() + "')";
}
draw();
for (let i = 0; i < 10; ++i)
selects[i].addEventListener("change", draw);
let saves = document.getElementsByClassName("butsave");
for (let i = 0; i < 4; ++i) {
saves[i].addEventListener("click", function(){
let output = new Uint8Array(1 + 10 + recolor.length);
output[0] = 0; //version
for (let i = 0; i < 10; ++i)
output[i + 1] = selects[i].selectedIndex;
output.set(recolor, 1 + 10);
//https://stackoverflow.com/questions/3665115/how-to-create-a-file-in-memory-for-user-to-download-but-not-through-server
const element = document.createElement('a');
element.setAttribute('href', window.URL.createObjectURL(new Blob([output])));
element.setAttribute('download', "Fur" + (i + 1) + ".asdat");
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
}
document.getElementById("butload").addEventListener("click", function() {
document.getElementById('hiddenload').click();
});
document.getElementById('hiddenload').addEventListener('change', function(evt) {
let f = evt.target.files[0];
if (f) {
if (f.name != "Fur1.asdat" && f.name != "Fur2.asdat" && f.name != "Fur3.asdat" && f.name != "Fur4.asdat") {
alert("Invalid filename");
return;
}
if (f.size != 1 + 10 + recolor.length) {
alert("Invalid filesize");
return;
}
const reader = new FileReader();
reader.onload = function() {
const result = new Uint8Array(reader.result);
let idx = 0;
if (result[idx++] > FILEVERSION) {
alert("File saved in a later version of TrueFur.html, please update your local copy.");
return;
}
for (let selectID = 0; selectID < 10; ++selectID)
selects[selectID].selectedIndex = result[idx++];
recolor = result.slice(idx);
for (let selectID = 0; selectID < 10; ++selectID)
selects[selectID].dispatchEvent(new Event("change"));
};
reader.readAsArrayBuffer(f);
}
}, false);
});
</script>
</body>
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.