JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

Griffin k/w/e calculator. For 'Shrine of the Griffin'. See how the black, white and exotic loci cause different colourings, and tortie markings in females.

<div class='container'>

<div id='mother' class='bg_mother'>Mother: <span id='parent_info_2'>Rainbow Tortie</span><br>
<div id='parent_coat_2' class='griffin_coat coat_adult'>Rendering...</div>
<select id='f_k1'> 
    <option value='K' selected>K</option>
    <option value='k'>k</option>
</select>
<select id='f_k2'>
    <option value='K'>K</option>
    <option value='k' selected>k</option>
</select> 
<select id='f_w1'>
    <option value='W'>W</option>
    <option value='w' selected>w</option>
</select>
<select id='f_w2'>
    <option value='W'>W</option>
    <option value='w' selected>w</option>
</select>
<select id='f_e1'>
    <option value='E'>E</option>
    <option value='e' selected>e</option>
</select>
<select id='f_e2'>
    <option value='E'>E</option>
    <option value='e' selected>e</option>
</select>
</div> 
<div id='father' class='bg_father'>Father: <span id='parent_info_1'>Non-rainbow</span><br>
<div id='parent_coat_1' class='griffin_coat coat_adult'>Rendering...</div>
<select id='m_k1'> 
    <option value='K' selected>K</option>
    <option value='k'>k</option>
</select>
<select id='m_w1'>
    <option value='W' selected>W</option>
    <option value='w'>w</option>
</select>
<select id='m_w2'>
    <option value='W'>W</option>
    <option value='w' selected>w</option>
</select>
<select id='m_e1'>
    <option value='E'>E</option>
    <option value='e' selected>e</option>
</select>
</div>
<br><button id='cross'>Cross</button><br>Here are the colours of potential offspring.<br>

<table id='result_table'></table>

</div>

CSS

.container {text-align:center;}
#mother, #father {border:1px solid black;padding:10px;margin:5px;border-radius:5px;display:inline-block;vertical-align:top;}

table {
    width: 100%;
    border-collapse: collapse;
    margin: 20px auto;
}

table td {
    border: 1px solid #ddd;
    padding: 5px;
    text-align: center;
}

table .empty {
    border: none;
}
table .header {
    font-weight: bold;
    /*background-color: #ddd;*/
    border: 1px solid #bbb;
}

.bg_father {
    background-color: #bbe0f7;
}
.bg_mother {
    background-color: #f2c7f3;
}
.bg_tortie {
    background-image: url("https://a.deviantart.net/avatars-big/i/c/icestar142.png");
}

.griffin_coat {
    position: relative;
}
.griffin_coat img {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
}

.coat_adult {
    width: 400px;
    height: 300px;
}
.coat_teen {
    width: 400px;
    height: 300px;
}

/* Same for all stages. */
.coat_bigthumb {
    width: 200px;
    height: 150px;
}
.coat_thumb {
    width: 160px;
    height: 120px;
}
.coat_small {
    width: 120px;
    height: 90px;
}
.coat_tiny {
    width: 100px;
    height: 75px;
}



.multiply {
  mix-blend-mode: multiply;
}
.overlay {
  mix-blend-mode: soft-light;
}

/* 
    Classes for each coat colour.
    'f' means filters for black PNG images.
    'c' means background colour for divs.
    1-4 are shades: Base, Faded, Bright, Cream.
*/

/* Red, salmon, amaranth, pink */
.c_red_1 {background-color: #ffcc33;}
.c_red_2 {background-color: #ffcc33;}
.c_red_3 {background-color: #ffcc33;}
.c_red_4 {background-color: #ffcc33;}
.f_red_1 {filter: invert(13%) sepia(59%) saturate(5042%) hue-rotate(354deg) brightness(81%) contrast(90%);}
.f_red_2 {filter: invert(41%) sepia(14%) saturate(6118%) hue-rotate(337deg) brightness(92%) contrast(85%);}
.f_red_3 {filter: invert(58%) sepia(73%) saturate(483%) hue-rotate(308deg) brightness(100%) contrast(108%);}
.f_red_4 {filter: invert(86%) sepia(68%) saturate(1606%)...

JavaScript

const path = 'http://mythstable.epizy.com/ootg/images/';

// For assembling image HTML.
class Coat {
    constructor(sex, stage, size = ""){
        this.path = path + stage + "/";
        if(stage > 3){ this.path += sex + "/"; }
        if(size != ""){ this.path += size + "/"; }
        this.startCoat();
    }
    
    startCoat(){
        this.html = "<img src='" + this.path + "ground.png'>\n";
    }
    
    addImage(url){
        this.html += "<img src='" + this.path + url + ".png'>\n";
    }
    
    addFilter(url, css){
        this.html += "<img src='" + this.path + url + ".png' class='f_" + css + "'>\n";
    }
    
    endCoat(){
        this.html += "<img src='" + this.path + "shade.png' class='multiply'>\n";
        this.html += "<img src='" + this.path + "shade.png' class='overlay' style='opacity:0.3;'>\n";
        this.html += "<img src='" + this.path + "line.png'>\n";
    }
    
    output(){
        return this.html;
    }
}

// Handle the Black/White/Exotic punnett square.
class KWECalc {
    constructor(){
        this.mother = {sex: 2, k1: "K", k2: "k", w1: "w", w2: "w", e1: "e", e2: "e"};
        this.father = {sex: 1, k1: "k", w2: "W", w1: "W", e1: "E"};
        
        this.updateParent(this.mother);
        this.updateParent(this.father);
    }
    
    orderGenes(g){
        if(g.sex == 2){
            if(g.k1 == "k" && g.k2 == "K"){ g.k1 = "K"; g.k2 = "k"; }
            if(g.e1 == "e" && g.e2 == "E"){ g.e1 = "E"; g.e2 = "e"; }
        }
        if(g.w1 == "w" && g.w2 == "W"){ g.w1 = "W"; g.w2 = "w"; }
        return g;
    }
    
    updateMother(){
        this.mother = {
            sex: 2,
            w1: $("#f_w1").val(),
            w2: $("#f_w2").val(),
            k1: $("#f_k1").val(),
            k2: $("#f_k2").val(),
            e1: $("#f_e1").val(),
            e2: $("#f_e2").val()
        };
        this.updateParent(this.mother);
    }
    
    updateFather(){
        this.father = {
            sex: 1,
            w1:...