JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

Trying to use SVG to generate blobby shapes, to use as pied (or tortoiseshell) markings on griffin coat. They must use seed/slope/intercept values, so the same 3 numbers always results in same shape, when an individual griffin is loaded.<p>So far so good, but how to apply the shapes to coat area? The griffin below is brown, and should be partially covered in a patchy white layer. The white 'markings' mustn't extend outside the griffin outline. Two options: have a solid white griffin-shape and use the SVG to cut areas out of it, or use it as a mask to cut out excess areas of the SVG? I can't get either to work.</p> 
Seed: <input id='current_seed' type='number' min='1' max='10000' value='123'> | 
Slope: <input id='current_slope' type='number' min='800' max='1200' value='1000'> | 
Intercept: <input id='current_intercept' type='number' min='400' max='800' value='600'>

<p><button onclick="submitSeed()">Submit</button>
<button onclick="randomSeed()">Randomise!</button></p>

<svg viewBox="0 0 600 600">
    
        <!-- Simple circle test. Works. -->
        <mask id="circle">
            <circle id="outer" cx="250" cy="150" r="100" fill="white"/>
            <circle id="inner" cx="250" cy="150" r="50"/>
        </mask>
        
        
        <defs>
            <filter id="pied" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
            
                <!-- seed, zoom, octaves -->
                <feTurbulence id="turbulence" type="fractalNoise" seed="123" baseFrequency="0.004" numOctaves="5" result="noise">
                </feTurbulence>
                
                 <!-- water level -->
                 <feComponentTransfer in="noise" result="water_level">
                     <feFuncR id="water_level" type="linear" intercept="600" slope="-1000">
                     </feFuncR>
                     
                 </feComponentTransfer>
                 
                 <!-- black area -->
                 <feColorMatrix...

CSS

body {
    background-color: #ccc;
}

input {
    max-width: 80px;
}

#griffin_coat {
    width: 500px;
    height: 400px;
    margin: 15px;
    position: relative;
}
#griffin_coat img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
.brown_filter {
    filter: invert(35%) sepia(78%) saturate(313%) hue-rotate(353deg) brightness(97%) contrast(90%);
}
.white_filter {
    filter: invert(100%);
}

/* Tests. */
.circle_mask {
    -webkit-mask-image: url("#circle");
    mask-image: url("#circle");
}
.pattern_mask {
    -webkit-mask-image: url("#pattern");
    mask-image: url("#pattern");
}

/* This is the final, desired class. Patchy marks. */
.pied_mask {
    -webkit-mask-image: url("#pied");
    mask-image: url("#pied");
}

/*
    Trying opposite approach.
    Cutting out images to fill griffin shape only.
*/
.griffin_shape {
  -webkit-mask-image: url("http://mythstable.epizy.com/ootg/f_adult/base.png");
  mask-image: url("http://mythstable.epizy.com/ootg/f_adult/base.png");
}

.umm {
    mask-image: url("#umm");
}

.item {
  mask-image: url(https://img-fotki.yandex.ru/get/9492/5091629.9d/0_80e74_9f303e3d_M.png);
  mask-repeat: space;
  }

JavaScript

// Use random values.
function randomSeed(){
    var seed = Math.round(Math.random() * 10000);
    var slope = randomNumber(800, 1200);
    var intercept = randomNumber(400, 600);
    
    document.getElementById("current_seed").value = seed;
    document.getElementById("current_slope").value = slope;
    document.getElementById("current_intercept").value = intercept;
    
    generateMap(seed, slope, intercept);
}

// Use custom values, currently written in the inputs.
function submitSeed(){
    var seed = document.getElementById("current_seed").value;
    var slope = document.getElementById("current_slope").value;
    var intercept = document.getElementById("current_intercept").value;
    
    generateMap(seed, slope, intercept);
}

// Update the SVG.
function generateMap(seed, slope, intercept){
    document.getElementById("turbulence").setAttribute("seed", seed);
    document.getElementById("water_level").setAttribute("slope", 0 - slope);
    document.getElementById("water_level").setAttribute("intercept", intercept);
}


// Pick a random number between any two.
function randomNumber(n1, n2){
	if(n1 == n2){
        return n1;
    }
    var min = n1;
    var max = n2;
    if(n1 > n2){
        min = n2;
        max = n1;
    }
    return Math.floor(Math.random()*(max-min+1)+min);
}