Edward Delaporte created this art using the P5.js JavaScript library, and the following additional code:
brickwall
function setup_canvas(maxim_x=800, maxim_y=400) {
  midline = maxim_x / 2;
  myCanvas = createCanvas(maxim_x, maxim_y);
}
function zippy() {
  /// Dark Striped Background
  noStroke();
  stripe_w = 60;
  for(i=0; i<400; i++) {
    fill(fresh_color(.3)); // darker fill color
    x = i * stripe_w;
    // triangle(x, y, x+30, y-random(80), x, y+i+30);
    rect(x,0, stripe_w, 400);
  }
}
function setup_background_circles(centerx, max_diam){
  xo = centerx;
  yo = centerx;
  for(var i=0; i<9; i++){
    ccolor = fresh_color();
    diam = max_diam -i*20;
    fill(ccolor);
    circle(xo, yo, diam);
  }
}
function starfield(max_x, max_y, star_size=4) {
  // white stars
  noStroke();
  fill(color(255,255,255));
  
  // Randomly scatter stars.
  starcount = random(20,60);
  for(i=0;i<starcount;i++){
    starx = random(0, max_x);
    stary = random(0, max_y);
    circle(starx, stary, star_size);
    if(random(0,5)==1) {
      circle(starx -4, stary -4, star_size);
    }
  }
}
  
    
/* 
Reusable random functions
*/
function rando_url(){
  if(get_url_seed() == null) {
    new_random(Date.now());
  }
}
function random_plus_minus(low, high){
  // Return a random number with a random sign
  var plus_minus = Math.random() < 0.5 ? -1 : 1;
  var sel_val = low + Math.random()*(high-low);
  return sel_val * plus_minus;
}
function new_random(seed=null) {
  seed = get_random_seed(seed);
  window.location.search = "?r=" + seed;
}
function get_url_seed() {
  const params = new URLSearchParams(location.search);
  seed = params.get('r');
  return seed;
}
function get_random_between(low, high, seed) {
  if(!seed) {
    seed = get_url_seed();
  }
  return low + get_random_from_seed(seed, high);
}
function get_random_seed(seed=200) {
  rand = Math.random();
  rand = Math.sin(seed) * 10000;
  seed = rand - Math.floor(rand);
  return seed;
}
function get_random_from_seed(seed, max_r=1) {
    rand = Math.sin(seed) * 10000;
    rand = rand - Math.floor(rand); // Get remainder
    return Math.floor(rand * max_r);
}
var color_shift = 0;
function fresh_color(warmth=.7, seed) {
  if(!seed) {
    seed = get_url_seed();
    color_shift+=1;
    seed = seed^color_shift;
  }
  r1 = get_random_from_seed(seed, 255);
  r2 = get_random_from_seed(seed*r1, 255);
  r3 = get_random_from_seed(seed*r2, 255);
  return color(r1*warmth,r2*warmth,r3*warmth);
}
function fresher_color(warmth=.7, seed) {
  if(!seed) {
    seed = get_url_seed();
    color_shift+=1;
    seed = seed^color_shift;
  }
  r1 = 85 + get_random_from_seed(seed^color_shift, 170);
  color_shift+=random();
  r2 = 85 + get_random_from_seed(seed^color_shift, 170);
  color_shift+=random();
  r3 = 85 + get_random_from_seed(seed^color_shift, 170);
  color_shift+=random();
  return color(r1*warmth,r2*warmth,r3*warmth);
}
function remove_item(choices, item) {
  index = choices.indexOf(item);
  if (index > -1) { 
    choices.splice(index, 1); 
  }
  return choices;
}
function choose(choices, seed) {
  // Support repeatable result.
  // so that every frame of animation re-uses the 
  // same choice as last.
  if(!seed) {
    seed = get_url_seed();
  }
  index = get_random_from_seed(seed, choices.length);
  return choices[index];
}
  
    
let ani_stack = [];
let ani_stack_max = 30;
// Called to add a planned animation.
// item should be a function that adds calls for it's future steps via ani_setup
/*
Example:
        ani_plan( 
          item = 
          function() { 
            branch(x+wi, y-ta, nle, we*4/5, wi2, ta, pulse);
          }
        );
*/
function ani_setup(item) {
  if(ani_stack.length < ani_stack_max) {
    ani_stack.push(item);
  }
  // console.debug(ani_stack.length);
}
// Called at the start of setup
function ani_clear() {
  while(ani_stack.length > 0) {
    ani_stack.pop();
  }
}
// Call during draw
function ani_draw() {
  ani_speed = 4;
  for(ani_i = 0; ani_i < ani_speed; ani_i++) {
    if(ani_stack.length > 0) {
      anim = ani_stack.pop();
      anim();
    }
  }
}
  
    
function toRadians (angle) {
  return angle * (Math.PI / 180);
}
function add_degrees(angle, degrees) {
  updated = angle + degrees;
  if(updated > 360) {
    updated = updated - 360;
  }
  return updated;
}
var line_segment = {
  x: 0,
  y: 0,
  weight: 4,
  degrees: 0,
  length: 20,
  history: 0,
  color: null,
  color_seq: [],
};
function draw_line_segment(line_seg, hide=0) {
  seg = structuredClone(line_seg);
  seg.history+=1;
  // stroke(seg.color.red, seg.color.green, seg.color.blue);
  strokeWeight(seg.weight);
  angleRad = toRadians(seg.degrees);
  endx = seg.x + seg.length*Math.cos(angleRad);
  endy = seg.y + seg.length*Math.sin(angleRad);
  if(hide==0) {
    line(seg.x, seg.y, endx, endy);
  }
  next_seg = structuredClone(seg);
  next_seg.x = endx;
  next_seg.y = endy;
  return next_seg;
}
function draw_line_cross(line_seg, dx, dy, hide=0) {
  seg = structuredClone(line_seg);
  seg.history+=1;
  strokeWeight(seg.weight);
  angleRad = toRadians(seg.degrees + 90);
  endx = seg.x + .5*seg.length*Math.cos(angleRad);
  endy = seg.y + .5*seg.length*Math.sin(angleRad);
  startx = seg.x - .5*seg.length*Math.cos(angleRad);
  starty = seg.y - .5*seg.length*Math.sin(angleRad);
  if(hide==0) line(startx+dx, starty+dy, 
    endx+dx, endy+dy);
  /*
  next_seg = structuredClone(seg);
  next_seg.x = endx;
  next_seg.y = endy;
  return next_seg;
  */
}
function draw_line_with_kite_shadow(line_seg, color_seq) {
  // prep
  seg = structuredClone(line_seg);
  angleRad = toRadians(seg.degrees);
  endx = seg.x + seg.length*Math.cos(angleRad);
  endy = seg.y + seg.length*Math.sin(angleRad);
  if(line_seg.history > 0) { // skip first line
  // draw shadow
  shadow_idx = (seg.history % color_seq.length);
  sha_c = color_seq[shadow_idx];
  stroke(sha_c.red, sha_c.green, sha_c.blue);
  fill(sha_c);
  swe = seg.weight*16;
  quad(
    seg.x,seg.y, 
    seg.x+swe,seg.y+swe, 
    endx,endy,
    endx+swe,endy+swe
    );
  // draw line
  stroke(seg.color.red, seg.color.green, seg.color.blue);
  strokeWeight(seg.weight);
  line(seg.x, seg.y, endx, endy);
  } else {
    endx = seg.x;
    endy = seg.y;
  }
  // house keeping
  seg.history+=1;
  next_seg = structuredClone(seg);
  next_seg.x = endx;
  next_seg.y = endy;
  return next_seg;
}
function new_line_segment(color_seq) {
  seg = structuredClone(line_segment);
  seg.color_seq = color_seq;
  seg.color = seg.color_seq[0];
  return seg;
}
  
    
/*
This is a Live Art work created by Edward Delaporte.
This script is Copyright Edward Delaporte 2021.
This script and the art it creates are licensed under 
a Creative Commons Attribution-ShareAlike 4.0 
International License.
http://creativecommons.org/licenses/by-sa/4.0/
You can share your own remix of this code 
as long as you display this license and attribution.
*/
var color_seq = [];
function start_fractal(color_seq) {
  line_bit = new_line_segment(color_seq);
  line_bit.y = 250;
  line_bit.length = 90;
  line_bit.x = 300;
  line_bit.degrees = 0; 
  roty = 52;
  do_fractal(line_bit);
  line_bit.degrees+=roty;
  do_fractal(line_bit);
  line_bit.degrees+=roty;
  do_fractal(line_bit);
  line_bit.degrees+=roty;
  do_fractal(line_bit);
  line_bit.degrees+=roty;
  do_fractal(line_bit);
}
var first_angle = get_random_between(30, 120);
console.log("1:" + first_angle);
var second_angle = get_random_between(45, 60);
console.log("2:" + second_angle);
async function do_fractal(bit) {
  if(bit.history == 3) {
    bit.color = bit.color_seq[1];
  }
  if(bit.history == 6) {
    bit.color = bit.color_seq[2];
  }
  if(bit.history == 9) {
    bit.color = bit.color_seq[3];
  }
   stroke(bit.color.levels[0],
          bit.color.levels[1],
          bit.color.levels[2]);
  hide=0;
  if(bit.history<3) {
    hide=1;
  }
  const next_bit = structuredClone(draw_line_segment(bit, hide));
  for(i=3; i<5; i+=bit.weight*2){
    draw_line_cross(bit, i, i, hide);
  }
  next_bit.length = next_bit.length*.67;
  next_bit.weight = next_bit.weight*.67;
  next_bit.degrees = add_degrees(bit.degrees, first_angle);
  if(next_bit.length > 4) {
    ani_setup( 
        item = function() { 
          do_fractal(next_bit);
          const bit2 = structuredClone(next_bit);
          bit2.degrees = add_degrees(bit.degrees, second_angle);
          do_fractal(bit2);
          /*
          if(second_angle < 60) {
            const bit3 = structuredClone(next_bit);
            bit3.degrees = add_degrees(bit.degrees, second_angle*2);
            do_fractal(bit3);
          }
          */
        }
    );
  }
}
function setup() {
  rando_url();
  ani_clear();
  color_seq = [
    color(0,60,60),
    color(7,44,63),
    color(24,101,142),
    color(11,156,234),
  ];
  second_angle = random_plus_minus(30, 140);
  maxim_x = 600;
  maxim_y = 500;
  midline = maxim_y / 2;
  myCanvas = createCanvas(maxim_x, maxim_y);
  myCanvas = createCanvas(maxim_x, maxim_y);
  fill(240,240,240);
  circle(maxim_x/2, maxim_y/2, maxim_y*.8);
  fill(255,255,255);
  circle(maxim_x/2, maxim_y/2, maxim_y*.7);
  start_fractal(color_seq);
  console.log("setup done");
}
function mouseClicked() {
  new_random(get_url_seed());
}
function draw() {
  ani_draw();
}
  
This work ©2020-2025 by Edward Delaporte is licensed under CC BY-NC-SA 4.0