<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  width="200"
  height="200"
  viewBox="0 0 100 100"
  role="img"
  aria-labelledby="title"
>
  <title id="title">
    Shining Some Light
  </title>
  
  <defs>
    <filter id="my-filter">
      <feTurbulence baseFrequency="0.1" seed="0" numOctaves="1" />
      <feDiffuseLighting lighting-color="DodgerBlue" surfaceScale="10">
        <feDistantLight azimuth="45" elevation="60"></feDistantLight>
      </feDiffuseLighting>
      <feComposite operator="in" in2="SourceGraphic"></feComposite>
    </filter>
  </defs>
  
  <circle cx=
"50" cy="50" r="50" filter="url('#my-filter')" />
</svg>

<form>
  <div class="form-chunk" id="turbulence-settings">
    <h2>Turbulence</h2>
    <fieldset>
      <legend>Base Frequency</legend>
        <div>
          <label for="baseFrequencyX">x</label>
          <input type="range" name="baseFrequencyX" id="baseFrequencyX" value="0.1" min="0.01" max="2" step="0.01">
          <span aria-hidden="true" id="baseFrequencyXDisplay">0.01</span>
        </div>
        <div>
          <label for="baseFrequencyY">y</label>
          <input type="range" name="baseFrequencyY" id="baseFrequencyY" value="0.1" min="0.01" max="2" step="0.01">
          <span aria-hidden="true" id="baseFrequencyYDisplay">0.01</span>
        </div>
      </fieldset>
    <fieldset>
      <legend>Type</legend>
      <div>
        <input type="radio" name="type" id="turbulence" value="turbulence" checked>
        <label for="turbulence">Turbulence</label>
      </div>
      <div>
        <input type="radio" name="type" id="fractalNoise" value="fractalNoise">
        <label for="fractalNoise">Fractal Noise</label>
      </div>
    </fieldset>

    <div class="fake-fieldset">
      <label class="fake-legend" for="seed">Seed</label>
      <input type="number" name="seed" id="seed" value="0" />
    </div>

    <div class="fake-fieldset">
      <label class="fake-legend" for="numOctaves">Octaves</label>
      <input type="number" name="numOctaves" id="numOctaves" value="1" />
    </div>
  </div>
  
  <div class="form-chunk" id="lighting-settings">
    <h2>Diffuse Lighting</h2>

    <div class="fake-fieldset">
      <label class="fake-legend" for="color">Color</label>
      <input type="color" name="lighting-color" id="color" value="#1e90ff" data-target="feDiffuseLighting"/>
    </div>

    <div class="fake-fieldset">
      <label class="fake-legend" for="surfaceScale">Surface Scale</label>
      <input type="number" name="surfaceScale" id="surfaceScale" value="10" data-target="feDiffuseLighting"/>
    </div>
    
    <h2>Distant Light</h2>

    <div class="fake-fieldset">
      <label class="fake-legend" for="elevation">Elevation</label>
      <input type="range" name="elevation" id="elevation" value="60" data-target="feDistantLight" min="0" max="360" step="1" />
      <span aria-hidden="true" id="elevationDisplay">60</span>
    </div>

    <div class="fake-fieldset">
      <label class="fake-legend" for="azimuth">Azimuth</label>
      <input type="range" name="azimuth" id="azimuth" value="45" min="0" max="360" step="1" data-target="feDistantLight"/>
      <span aria-hidden="true" id="azimuthDisplay">45</span>
    </div>
   </div>
</form>
body, html {
  align-items: center;
  justify-content: center;
  margin: 0; 
  display: flex; 
  min-height: 100%; 
  width: 100%;
}

* {
  font-family: sans-serif;
  box-sizing: border-box;
}

fieldset > div + div {
  margin-top: 0.25em;
}

fieldset > div {
  display: flex;
  align-items: center;
}

* + fieldset,
* + .fake-fieldset {
  margin-top: 1em;
}

fieldset, .fake-fieldset {
  border: 1px solid #a0a0a0;
  padding: 0.5em 1em;
  position: relative;
}

.fake-fieldset {
  padding-top: 1em;
  display: flex;
  align-items: center;
}

.fake-legend {
  position: absolute;
  left: 1em;
  top: -0.75em;
  font-weight: bold;
  background: #fff;
  padding: 0.25em;
}

input {
  margin-top: 0;
}

[type="range"] {
  margin: 0 0.5em;
  flex-grow: 1;
  width: calc(100% - 2em);
}

[type="number"],
[type="color"]{
  display: block;
  width: 100%;
  box-sizing: border-box;
}

legend {
  font-weight: bold;
}

form {
  display: flex;
  flex-wrap: wrap;
  max-width: 100%;
  overflow: hidden;
}

.form-chunk {
  margin-left: 1em;
  flex-grow: 1;
  flex-basis: 10em;
  flex-shrink: 1;
}

h2 {
  font-size: 1.5em;
}

svg {
  min-width: 8em;
}
const filter = document.querySelector('filter');
const turbulence = document.querySelector('feTurbulence');

let frequencyX = 0.1;
let frequencyY = 0.1;

document.querySelectorAll('#turbulence-settings input').forEach(input => {
  input.addEventListener('input', ({target}) => {
    const {name, value} = target;
    if(name === 'baseFrequencyX') {
      frequencyX = value;
      turbulence.setAttribute('baseFrequency', `${frequencyX} ${frequencyY}`)
      document.querySelector('#baseFrequencyXDisplay').textContent = frequencyX;
    } else if(name === 'baseFrequencyY') {
      frequencyY = value;
      turbulence.setAttribute('baseFrequency', `${frequencyX} ${frequencyY}`)
      document.querySelector('#baseFrequencyYDisplay').textContent = frequencyY;
    } else {
      turbulence.setAttribute(name, value);
    }
  });
});
document.querySelectorAll('#lighting-settings input').forEach(input => {
  input.addEventListener('input', ({target}) => {
    const {name, value, dataset} = target;
    
    document.querySelector(dataset.target).setAttribute(name, value);
    
    if(name === 'azimuth') {
      document.querySelector('#azimuthDisplay').textContent = value;
    } else if(name === 'elevation') {
      document.querySelector('#elevationDisplay').textContent = value;
    }
  }); 
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.