SOURCE

console 命令行工具 X clear

                    
>
console
var body = document.querySelector("body");
var root = document.querySelector("#root");
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
var globalIndex;
var colorFuncs = [extended10, triads, complements, desaturated, saturated, spectrum, analogs, splitComplements, shades, monochrome];
const blendModes = ["difference", "exclusion", "multiply", "darken", "lighten", "color", "luminosity", "saturation", "overlay", "hue", "soft-light", "hard-light", "screen", "color-burn", "color-dodge", "normal"];

/*color selection*/
var colorSelectionModes = ["random", "sequential"]
function getColor(opt) {
  let mode = globalOptions.overrides.colorSelection || opt.colorSelection
  let pal = globalOptions.overrides.paletteFunction != "" ? globalOptions.overrides.palette : opt.palette
  return mode = "random" ? pick(pal) : pal[globalIndex%pal.length]
}
/*inversion*/
var inversionModes = ["None", "All", "everyNth", "chance"]
function getInversion(opt) {
  
  let mode = globalOptions.overrides.inversionMode || opt.inversionMode
  let prob = globalOptions.overrides.inversionMode ? globalOptions.overrides.inversionProbability : opt.inversionProbability
  let every = globalOptions.overrides.inversionMode ? globalOptions.overrides.invertEvery : opt.invertEvery

  return mode == "None" ? false 
   : mode == "All" ? true
   : mode == "chance" ? chance(prob) ? true : false
   : globalIndex % every == 0 ? true : false
}

/*container rotations (angles)*/
var angles = [0, 45]
var angleModes = ["useAngle1", "angle2Probability", "angle2EveryNth"]
function getAngle(opt) {  
  
  let ov = globalOptions.overrides
  let mode = globalOptions.overrides.angleMode || opt.angleMode
  let prob = ov.angleMode ? ov.angle2Probability : opt.angle2Probability
  let every = ov.angleMode ? ov.angleSwitchEvery : opt.angleSwitchEvery
  let angle1 = ov.angleMode ? ov.angle1 : opt.angle1
  let angle2 = ov.angleMode ? ov.angle2 : opt.angle2
  
  switch(mode) {
    case "useAngle1":
      return angle1
      break;
    case "angle2Probability":
      return chance(prob) ? angle2 : angle1
      break;
    case "angle2EveryNth":
      return globalIndex % every == 0 ? angle2 : angle1;
      break;
  }
}

/*BORDER STYLEZ*/
var borderStyleModes = ["useBorder1", "randomSolidOrDouble", "switchStyleEvery"]
var regularBorderStyles = ["double", "solid"]
var allBorderStyles = ["double", "solid", "dashed", "dotted"]
function getBorderStyle(opt) {
  
  let ov = globalOptions.overrides
  let mode = ov.borderStyleMode || opt.borderStyleMode
  let every = ov.borderStyleMode ? ov.switchStyleEvery : opt.switchStyleEvery
  let style1 = ov.borderStyleMode ? ov.borderStyle1 : opt.borderStyle1
  let style2 = ov.borderStyleMode ? ov.borderStyle2 : opt.borderStyle2
    
  switch(mode){
    case "randomSolidOrDouble":
      return pick(regularBorderStyles)
      break;
    case "randomAllStyles":
      return pick(allBorderStyles)
      break;
    case "switchStyleEvery":
      return globalIndex % every == 0 ? style1 : style2
      break;
    case "useBorder1":
      return style1;
      break;      
  }
}

/*BORDER RaDIUS*/
var radiusModes = ["linesOnly", "circlesOnly", "useRadius1", "random1Or2", "range1Thru2", "radius2RandomNth"]
function getRadius(opt){
  
  let ov = globalOptions.overrides
  let mode = ov.radiusMode || opt.radiusMode
  let func;
  let radius1 = ov.radiusMode? ov.radius1 : opt.radius1;
  let radius2 = ov.radiusMode? ov.radius2 : opt.radius2;
 
  switch(mode){
    case "linesOnly" :
      return 0;
      break;
    case "circlesOnly" :
      return 50;
      break;
    case "useRadius1":
      return radius1
    case "random1Or2":
      return pick([radius1,radius2])
      break;
    case "range1Thru2":
      return getRandomInt(radius1, radius2)
      break;
    case "radius2RandomNth":
      return globalIndex%getRandomInt(0,20)==0?radius2:radius1
      break;
  }
  return  func;
}
/*cell WIDTH*/
var widthModes = {
  "sequentialByIndex":indexedWidth,
  "useRange":rangedWidth,
  "useValues":pick,  
}
var widthRanges = {
  //el.style.width = w%
  "default":[40,60],
  "full":[0,100],
  "large":[0,200],
  "firstHalf":[0,50],
  "secondHalf":[50,100],
  "cross":[47,53],
  "wideCross":[30,70],
  "static50":[50,50]
}
var widthValues = {
  "fivesFirstHalf":[5,10,15,20,25,30,35,40,45,50],
  "fivesAll":[5,10,15,20,25,30,35,40,45,50,55,60,65,70,85,90,95],
  "tensAll":[10,20,30,40,50,60,70],
  "tensLarge":[50,60,70,80,90],
  "thirds":[33,66,99],
  "quarters":[25,50,75,100],
  "clusterSparse":[35,50,65],
  "splashOuter":[1, 3, 5, 10, 15],
  "cross":[40,45,50,55,60],
  "fibonacci":[1, 2, 3, 5, 8, 13, 21, 34, 45, 79, 124],
  "4's":Array.from({length:25},(v,index)=>index*4+4)
}
function indexedWidth(index, min, max) {
  if(min==max) return index*min;
  if(Number.isInteger(min)) return index * getRandomInt(min, max)
  return index * getRandomFloat(min,max)
}
function rangedWidth(min, max) {
  return getRandomInt(min,max)
}
function getWidth(opt) {
 
  let ov = globalOptions.overrides
  let widthMode = ov.widthMode || opt.widthMode
  let range = ov.widthMode ? widthRanges[ov.widthRange] : widthRanges[opt.widthRange]
  let widthVals = ov.widthMode ? widthValues[ov.widthValues] : widthValues[opt.widthValues]
  let minScale = ov.widthMode ? ov.indexMinScale : opt.indexMinScale
  let maxScale = ov.widthMode ? ov.indexMaxScale : opt.indexMaxScale

  switch(widthMode){
    case "useRange" :
       return rangedWidth(range[0], range[1])
      break;
    case "sequentialByIndex" :
       return indexedWidth(globalIndex,minScale, maxScale);
      break;
    case "useValues":
       return widthVals[globalIndex%widthVals.length]
      break;
    default:
      console.log("error")
  }
  return opt;
}
/*END Cell Width*/

var template = `<div class="container">
  <div class="grid grid1">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid2">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid3">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid4">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid5">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid6">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid7">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid8">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid9">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
  <div class="grid grid10">
    <div class="ul"></div><div class="ur"></div>
    <div class="bl"></div><div class="br"></div>
  </div>
</div>`


$(root).click(handleClick)
var globalOptions = {};
handleClick()
async function handleClick(ev) {
  generateGrids(true);
}

function generateGrids(generateNewOptions){
  $('.container').remove()
  globalIndex = 0;    
  if(generateNewOptions) {

    globalOptions.seedColor = tinycolor.random().saturate(20).toHexString()
    globalOptions.backgroundColor = globalOptions.seedColor;
    globalOptions.overrides = getPaintingOptions(globalOptions)
    globalOptions.overrides.enable = true;
    //set most of the 'mode' type of globals to "unselected" - so that each pattern shares a few globals traits, but then the others are all randomized.
    ["cellMixBlend", "containerMixBlend", "paletteFunction", "colorSelection", "inversionMode", "borderWidth", "borderStyleMode", "radiusMode", "widthMode", "angleMode"].forEach(key=>{
      if(typeof globalOptions.overrides[key] == "number") {
        globalOptions.overrides[key] = chance(.1) ? -1 : globalOptions.overrides[key]
      } else if(typeof globalOptions.overrides[key] == "string") {
        globalOptions.overrides[key] = chance(.1) ? "" : globalOptions.overrides[key]
      }
    })

    globalOptions.opt1 = getPaintingOptions(globalOptions)
    globalOptions.opt1.className = "painting1"
    globalOptions.opt1.enable = true;

    globalOptions.opt2 = getPaintingOptions(globalOptions)
    globalOptions.opt2.className = "painting2"
    globalOptions.opt2.enable = chance(.2);

    globalOptions.opt3 = getPaintingOptions(globalOptions)
    globalOptions.opt3.className = "painting3"
    globalOptions.opt3.enable = chance(.4);
    
    let twoAndThreeDisabled = !globalOptions.opt2.enable && !globalOptions.opt3.enable

    globalOptions.overrides.minIterations = twoAndThreeDisabled ? 5 : 2
    globalOptions.overrides.maxIterations = isMobile ? 3 : twoAndThreeDisabled ? 10 : 6;
    //possibly make the three sets of options share the exact same palette:
    if(chance(.7)) {
      globalOptions.opt2.palette = globalOptions.opt1.palette
      globalOptions.opt2.paletteFunction = globalOptions.opt1.paletteFunction
      globalOptions.opt3.palette = globalOptions.opt1.palette
      globalOptions.opt3.paletteFunction = globalOptions.opt1.paletteFunction
    }
    genGui(globalOptions);
  }
  let bg = chance() ? tinycolor(globalOptions.seedColor).lighten(30).toHexString() 
  : chance() ? tinycolor(globalOptions.seedColor).darken(30).toHexString() 
  : globalOptions.seedColor;
  globalOptions.backgroundColor = bg;
  body.style.backgroundColor =  bg;

  for(let i=0;i<=getRandomInt(globalOptions.overrides.minIterations,globalOptions.overrides.maxIterations);i++) {
    if(globalOptions.opt1.enable) buildPainting(globalOptions.opt1);
    if(globalOptions.opt2.enable) buildPainting(globalOptions.opt2)
    if(globalOptions.opt3.enable) buildPainting(globalOptions.opt3)
  }

  showGrids();

}

function getPaintingOptions(globals) {
    var paintOpt = {};   
    var colorFunc = pick(colorFuncs);
    var pal = colorFunc(globals.seedColor);
    
    paintOpt.paletteFunction = colorFunc.name
    paintOpt.palette = Object.values(pal) 
    paintOpt.colorSelection = pick(colorSelectionModes)
    paintOpt.containerMixBlend = chance() ? "difference" : pick(blendModes)
    paintOpt.cellMixBlend = chance() ? "difference" : pick(blendModes)
    paintOpt.inversionMode = chance()? "None" : pick(inversionModes)
    paintOpt.inversionChance = pick([0,1,.5, Math.random()])
    paintOpt.invertEvery = getRandomInt(2,11)
   
    paintOpt.radiusMode = pick(radiusModes)
    paintOpt.radius1 = chance() ? 50 : getRandomInt(0,50)
    paintOpt.radius2 = chance() ? 0 : getRandomInt(0,50)
  
    paintOpt.borderStyleMode = pick(borderStyleModes)
    paintOpt.switchStyleEvery = getRandomInt(1,20)
    paintOpt.borderStyle1 = pick(regularBorderStyles)
    paintOpt.borderStyle2 = pick(regularBorderStyles)
    paintOpt.borderWidth = getRandomInt(1,30)
    paintOpt.onlyInnerBorders = chance(.7)
    paintOpt.onlyOuterBorders = !paintOpt.onlyInnerBorders && chance(.8)
  
    paintOpt.angleMode = pick(angleModes)
    paintOpt.angle1 = pick(angles)
    paintOpt.angle2 = paintOpt.angle1 == 45 ? 0 : 45
    paintOpt.angle2Probability = Math.random()
    paintOpt.angleSwitchEvery = getRandomInt(2,17)
  
    paintOpt.scale = chance() ? 1 : getRandomFloat(.2,1.1)
    let indexMultiplier = chance() ? 1 : getRandomFloat(.1, 1);
    paintOpt.indexMinScale = indexMultiplier
    paintOpt.indexMaxScale = indexMultiplier
    paintOpt.widthRange = pick(Object.keys(widthRanges))
    paintOpt.widthValues = pick(Object.keys(widthValues))
    paintOpt.widthMode = pick(Object.keys(widthModes))   

    return paintOpt
  }

function buildPainting(options){
  var container = $(template);
  container.addClass(options.className)
  
  fireGrid(container, ".grid1", options);
  fireGrid(container, ".grid2", options);
  fireGrid(container, ".grid3", options);
  fireGrid(container, ".grid4", options);
  fireGrid(container, ".grid5", options);
  fireGrid(container, ".grid6", options);
  fireGrid(container, ".grid7", options);
  fireGrid(container, ".grid8", options);
  fireGrid(container, ".grid9", options);
  fireGrid(container, ".grid10", options);
}

function fireGrid(container, id, options) {
  let localIndex = id.match(/\d+/)[0];//not used
  var grid = container[0].querySelector(id)
  var min = Math.min(grid.clientWidth, grid.clientHeight);
  //console.log("minimum dimension"+min);
  var angle = getAngle(options)
  let width = getWidth(options)
  
  grid.style.filter = getInversion(options) ? "invert(100%)" : "invert(0%)";
  grid.style.transform = `rotate(${angle}deg) scale(${globalOptions.overrides.scale > 0 ? globalOptions.overrides.scale : options.scale})`;
  
  grid.style.mixBlendMode = globalOptions.overrides.containerMixBlend || options.containerMixBlend;
  var height = width;
  var borderSize = globalOptions.overrides.borderWidth != -1 ? globalOptions.overrides.borderWidth : options.borderWidth;
  var borderRadius = getRadius(options)
  var borderStyle = getBorderStyle(options)
  var color = getColor(options);
  
  [...grid.querySelectorAll(".ul, .ur, .bl, .br")].forEach((el,i) => {
    el.style.mixBlendMode = globalOptions.overrides.cellMixBlend || options.cellMixBlend;
    el.style.width = width+"%"
    el.style.height = height+'%'
    el.style.borderWidth = borderSize+"px";
    el.style.borderColor =  color;
    el.style.borderStyle = borderStyle;
    el.style.borderRadius = borderRadius+'%'    
    //inner borders only
    if(options.onlyInnerBorders) switch(el.className) {
        case "ul":
          el.style.borderTop = "none";
          el.style.borderLeft = "none";
          break;
        case "ur":
          el.style.borderTop = "none";
          el.style.borderRight = "none";
          break;
        case "bl":
          el.style.borderBottom = "none";
          el.style.borderLeft = "none";
          break;
        case "br":
          el.style.borderBottom = "none";
          el.style.borderRight = "none";
          break;
      }
    //outer borders only
    if(options.onlyOuterBorders) switch(el.className) {
        case "ul":
          el.style.borderBottom = "none";
          el.style.borderRight = "none";
          break;
        case "ur":
          el.style.borderBottom = "none";
          el.style.borderLeft= "none";
          break;
        case "bl":
          el.style.borderTop = "none";
          el.style.borderRight = "none";
          break;
        case "br":
          el.style.borderLeft = "none";
          el.style.borderTop = "none";
          break;
      }
  })
  $(root).append(container);
  globalIndex++;
}

async function showGrids(){
  let count = $(".grid:visible").length;
  //console.log("count visible:"+count);
  var el = $(".grid").not(":visible").first();
  if(el.length==0) {
   return false; 
  }
  el.show();
  await delay(Math.max(70-count),0);
  showGrids();
}

/*Utility Functions*/
function delay(ms) {
  return new Promise(done => setTimeout(() => {
    done()
  }, ms))
}
function getRandomInt(min, max) {
  min = Math.ceil(min)
  max = Math.floor(max)
  return Math.floor(Math.random() * (max - min + 1)) + min
}
function getRandomFloat(min, max) {
  return Math.random()*(max-min)+min;
}
function pick(arr) {
  if(!Array.isArray(arr)) return arr;
  return arr[Math.floor(Math.random() * arr.length)]
}
function chance(threshold=.5){   
  return Math.random()>threshold;
}
function padHex(h) {
  while(h.length<6){
    h = "0"+h
  }
  return '#'+h
}
function isIterable(obj) {
  return Array.isArray(obj) || obj == '[object NodeList]'
}
function odd() {
  return globalIndex%2!=0;
}
/*End Utility Funcs*/

/* from Palette Panda: https://codepen.io/sweaver2112/pen/NWKrXmG */
function spectrum(hex) {
  let c1 = tinycolor(hex).spin(-144).toHexString()
  let c2 = tinycolor(hex).spin(-72).toHexString()
  let c3 = hex
  let c4 = tinycolor(hex).spin(72).toHexString()
  let c5 = tinycolor(hex).spin(144).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function desaturated(hex) {
  const desatFactor = (tinycolor(hex).toHsl().s / 2) * 100
  let isDark = tinycolor(hex).isDark()
  let c1 = isDark ? tinycolor(hex).desaturate(desatFactor).brighten(20).toHexString() : tinycolor(hex).desaturate(desatFactor).darken(20).toHexString()
  let c2 = tinycolor(hex).desaturate(desatFactor).spin(120).toHexString()
  let c3 = tinycolor(hex).desaturate(desatFactor).toHexString()
  let c4 = tinycolor(hex).desaturate(desatFactor).spin(30).lighten(5).toHexString()
  let c5 = tinycolor(hex).desaturate(desatFactor).spin(90).toHexString()   
  return new Palette(c1, c2, c3, c4, c5)
}
function saturated(hex) {
  const satFactor = (tinycolor(hex).toHsl().s / 2) * 100
  let c1 = tinycolor(hex).spin(30).saturate(satFactor).lighten(10).toHexString()
  let c2 = tinycolor(hex).spin(15).saturate(satFactor).darken(10).toHexString()
  let c3 = tinycolor(hex).saturate(satFactor).toHexString()
  let c4 = tinycolor(hex).saturate(satFactor).spin(90).toHexString()
  let c5 = tinycolor(hex).saturate(satFactor).spin(120).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function triads(hex) {

  let c1 = tinycolor(hex).desaturate(10).lighten(15).toHexString()
  let c2 = tinycolor(hex).spin(-120).toHexString()
  let c3 = hex
  let c4 = tinycolor(hex).spin(120).toHexString()
  let c5 = tinycolor(hex).spin(120).saturate(10).darken(15).toHexString() 
  return new Palette(c1, c2, c3, c4, c5)
}
function analogs(hex) {

  let c1 = tinycolor(hex).spin(-30).toHexString()        
  let c2 = tinycolor(hex).spin(-15).saturate(10).darken(10).toHexString()        
  let c3 = hex
  let c4 = tinycolor(hex).spin(15).desaturate(10).lighten(10).toHexString()
  let c5 = tinycolor(hex).spin(30).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function splitComplements(hex) {

  let c1 = tinycolor(hex).spin(-150).saturate(10).darken(10).toHexString()
  let c2 = tinycolor(hex).spin(-150).toHexString()
  let c3 = hex
  let c4 = tinycolor(hex).spin(150).toHexString()
  let c5 = tinycolor(hex).spin(150).desaturate(10).lighten(10).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function monochrome(hex) {

  let isDark = tinycolor(hex).isDark()
  let c1 = isDark ? tinycolor(hex).lighten(25).toHexString() : tinycolor(hex).darken(25).toHexString()
  let c2 = isDark ? tinycolor(hex).desaturate(25).lighten(5).toHexString() : tinycolor(hex).desaturate(25).darken(5).toHexString()
  let c3 = hex
  let c4 = isDark ? tinycolor(hex).saturate(25).lighten(5).toHexString() : tinycolor(hex).saturate(25).darken(5).toHexString()
  let c5 = isDark ? tinycolor(hex).lighten(35).toHexString() : tinycolor(hex).darken(35).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function shades(hex) {

  let c1 = tinycolor(hex).lighten(30).toHexString()
  let c2 = tinycolor(hex).lighten(15).toHexString()
  let c3 = hex
  let c4 = tinycolor(hex).darken(15).toHexString()
  let c5 = tinycolor(hex).darken(30).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function complements(hex) {

  let isDark = tinycolor(hex).isDark()
  let c1 = tinycolor(hex).saturate(10).darken(15).toHexString()
  let c2 = tinycolor(hex).desaturate(10).lighten(15).toHexString()
  let c3 = hex
  let c4 = tinycolor(hex).spin(180).toHexString()
  let c5 = isDark ? tinycolor(hex).spin(180).desaturate(10).lighten(15).toHexString() : tinycolor(hex).spin(180).saturate(10).darken(15).toHexString()
  return new Palette(c1, c2, c3, c4, c5)
}
function rgb(){
  return new Palette("#ff0000","#00ff00","#0000ff");
}
function extended10(hex){
  let c1 = tinycolor(hex).spin(10).toHexString()
  let c2 = tinycolor(c1).spin(10).toHexString()
  let c3 = tinycolor(c2).spin(10).toHexString()
  let c4 = tinycolor(c3).spin(10).toHexString()
  let c5 = tinycolor(c4).spin(10).toHexString()
  let c6 = tinycolor(c5).spin(10).toHexString()
  let c7 = tinycolor(c6).spin(10).toHexString()
  let c8 = tinycolor(c7).spin(10).toHexString()
  let c9 = tinycolor(c8).spin(10).toHexString()
  let c10 = tinycolor(c9).spin(10).toHexString()
  return new Palette(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
}
function Palette(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) {
  this.c1 = c1
  this.c2 = c2
  this.c3 = c3
  this.c4 = c4
  this.c5 = c5;
  c6 && (this.c6 = c6)
  c7 && (this.c7 = c7)
  c8 && (this.c8 = c8)
  c9 && (this.c9 = c9)
  c10 && (this.c10 = c10)
}
//end Palette Panda
       
//DAT GUI
var wasOpen;
var gui;

function genGui(options) {
  
  //for the regular patterns (no blank values)
  var lists = {
    "blendModes":blendModes,
    "colorFuncs": colorFuncs.map(p=>p.name), 
    "colorSelectionModes": colorSelectionModes, 
    "inversionModes": inversionModes, 
    "borderStyleModes":borderStyleModes, 
    "allBorderStyles":allBorderStyles, 
    "radiusModes":radiusModes, 
    "widthModes":Object.keys(widthModes), 
    "widthRanges":Object.keys(widthRanges), 
    "widthValues":Object.keys(widthValues), 
    "angleModes": angleModes
  }
   
  //for the global overrides (allow "blank" choice)
   let withBlankValues = {}
   for(const key in lists) {
     withBlankValues[key] = ["", ...lists[key]]
   }
  
    wasOpen = gui && !gui.closed;
    gui && gui.destroy();
    gui = new dat.GUI();    
    if(!wasOpen) gui.close();
        
    gui.addColor(options,"seedColor").onChange((val)=>{
      globalOptions.opt1.palette = Object.values(colorFuncs.filter((f)=>f.name==globalOptions.opt1.paletteFunction)[0](val))
      globalOptions.opt2.palette = Object.values(colorFuncs.filter((f)=>f.name==globalOptions.opt2.paletteFunction)[0](val))
      globalOptions.opt3.palette = Object.values(colorFuncs.filter((f)=>f.name==globalOptions.opt3.paletteFunction)[0](val))

    })
    gui.addColor(options, "backgroundColor").onChange(val=>body.style.backgroundColor = val).listen()
    gui.add(globalOptions.overrides, "minIterations").min(-1).max(20).step(1)
    gui.add(globalOptions.overrides, "maxIterations").min(-1).max(20).step(1)
       
  
    var f4 = gui.addFolder("Global overrides") 
    f4.patternId = "Overrides"
    addFolder(f4,options.overrides, withBlankValues)

    var f1 = gui.addFolder("Pattern 1");
    f1.patternId = "Pattern 1"
    var f2 = gui.addFolder("Pattern 2");
    f2.patternId = "Pattern 2"
    var f3 = gui.addFolder("Pattern 3");
    f3.patternId = "Pattern 3"
    addFolder(f1, options.opt1, lists)
    addFolder(f2, options.opt2, lists)
    addFolder(f3, options.opt3, lists)
    var regenButton = { regenerate:function(){ 
      generateGrids(false)
    }}
    gui.add(regenButton,'regenerate');
    var randomizeButton = { randomize:function(){ 
      generateGrids(true)
    }}
    gui.add(randomizeButton,'randomize');
  
   function addFolder(f1, options, lists) {
     
     if(f1.patternId!="Overrides") {
       f1.add(options, "enable").onChange((val)=>{
         let selector = f1.patternId == "Pattern 1" ? ".painting1" 
         : f1.patternId == "Pattern 2" ? ".painting2" 
         : f1.patternId == "Pattern 3" ? ".painting3" : "";
         if(selector!="") $(selector).css("display", options.enable ? "block" : "none")
       })
     }

     let ff1 = f1.addFolder("Color Options")
     ff1.add(options, "cellMixBlend", lists["blendModes"]).onChange((val)=>setMixBlend(f1, "cellMixBlend", val))
     ff1.add(options, "containerMixBlend", lists["blendModes"]).onChange((val)=>setMixBlend(f1, "containerMixBlend", val))
     ff1.add(options, "paletteFunction", lists["colorFuncs"]).onChange((val)=>{
       options.palette = Object.values(colorFuncs.find((func)=>func.name==val)(globalOptions.seedColor))     
     })
     ff1.add(options, "colorSelection", lists["colorSelectionModes"])
     ff1.add(options, "inversionMode", lists["inversionModes"])
     ff1.add(options, "inversionChance").min(0).max(1).step(.1)
     ff1.add(options, "invertEvery").min(0).max(50).step(1)

     let ff0 = f1.addFolder("Border Options")   
     ff0.add(options, "borderWidth").min(-1).max(200).step(1)
     ff0.add(options, "borderStyleMode", lists["borderStyleModes"])
     ff0.add(options, "borderStyle1", lists["allBorderStyles"])
     ff0.add(options, "borderStyle2", lists["allBorderStyles"])
     ff0.add(options, "switchStyleEvery").min(-1).max(50).step(1)
     ff0.add(options, "radiusMode", lists["radiusModes"])
     ff0.add(options, "radius1").min(-1).max(50).step(1)
     ff0.add(options, "radius2").min(-1).max(50).step(1)
     if(f1.patternId!="Overrides") ff0.add(options, "onlyInnerBorders")
     if(f1.patternId!="Overrides") ff0.add(options, "onlyOuterBorders")

     let ff2 = f1.addFolder("Size Options")
     ff2.add(options, "scale").min(-1).max(10)
     ff2.add(options, "widthMode", lists["widthModes"])
     ff2.add(options, "widthRange", lists["widthRanges"])
     ff2.add(options, "widthValues", lists["widthValues"])
     ff2.add(options, "indexMinScale")
     ff2.add(options, "indexMaxScale")

     let ff3 = f1.addFolder("Rotation Options")
     ff3.add(options, "angleMode", lists["angleModes"])
     ff3.add(options, "angle1").min(0).max(90).step(1)
     ff3.add(options, "angle2").min(0).max(90).step(1)
     ff3.add(options, "angle2Probability")
     ff3.add(options, "angleSwitchEvery")
   }
}
function setMixBlend(folder, blendModeProperty, mixBlend) {
  let selector = (folder.patternId == "Pattern 1" ? ".painting1" 
    : folder.patternId == "Pattern 2" ? ".painting2" : folder.patternId == "Pattern 3" ? ".painting3" : "");
  if(selector!="") $(`${selector} ${blendModeProperty=="cellMixBlend" ? ".grid":""}`).css("mixBlendMode", mixBlend); 
       
  
}
<div id="root"></div> 
<p id="controls"></p>
body {
  font-family: "La Belle Aurore";
  background-color:beige;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100vw;
  color: white;
  box-sizing: border-box;
  transition:background-color 1s;
}
#root {
  height: 100vmin;
  width: 100vmin;
  flex 1 1 auto;
}
#controls {
  z-index:10;
}
.container {
  width: 100vmin;
  height: 100vmin;
  position:absolute;
  
}
div.grid:last-child {

}

.grid {
  width: 100vmin;
  height: 100vmin;
  position: absolute;
  top: 0;
  left: 0;
  display: none;
}
.grid div {
  position: absolute;  
  
 
}
.bl, .br {
  
}
.ul {
  top: 0;
  left: 0;
}
.ur {
  top: 0;
  right: 0;

}
.bl {
  bottom: 0;
  left: 0;

}
.br {
  bottom: 0;
  right: 0;
}
.dg .function div {
  font-size:110%;
  color:#7ff900;
}

本项目引用的自定义外部资源