The above 4 images show several iterations of my code below. I had a lot of fun experimenting with creating a kaleidoscope effect by overlapping several dynamic circles (their shapes were altered/deformed using noise) at varying opacities, colour schemes/noise-based gradients, and offsets. Like in the noise tutorial from class, I decided to create the background with a dynamic gradient of colours also controlled by offset noise. Originally the circles used a similar rainbow noise gradient, but I felt that I wanted to create more contrast between the background and circles. I experimented (as shown above) with white, black, grey, and blue. It appeared that using other solid colours like red, green, and yellow didn’t create enough contrast.

I find it really cool how the circles are not the “main” kaleidoscope shapes but are used to create negative space that cuts through the background in order to create the effect. I added a basic outlined square to the tile pattern to add more-dynamic overlay effects. The brightness and opacity of the squares are controlled using horizontal mouse movements.

```
// Title: 2D Perlin Simplex Noise V12

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.142

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

//Book of Shaders Simplex Noise (based off Ian McEwan, Ashima Arts)
// Some useful functions
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }

float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x &amp;amp;gt; x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

float map (float value, float min1, float max1, float min2, float max2){
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

//rotation functions from the Book of Shaders "Patterns"
vec2 rotate2D(vec2 st, float angle){
st -= 0.5;
st = mat2(cos(angle), -sin(angle),
sin(angle), cos(angle))*st;
st += 0.5;
return st;

}

vec2 rotateTilePattern(vec2 st){

//scale coordinate system by 2x2
st *= 6.0;

//give each cell and index number according to its position
float i = 0.0;
i += step(1.0, mod(st.x,2.0));
i += step(1.0, mod(st.y,2.0))*2.0;

//each cell between 0.0 -1.0
st = fract(st);

//rotate each cell according to index
//use matrix to rotate the space

if(i == 1.0){
st = rotate2D(st, PI*-0.5);
} else if (i == 2.0){
st = rotate2D(st, PI*0.5);
} else if (i == 3.0){
st = rotate2D(st, PI*2.0);
} else if (i== 0.0){
st = rotate2D(st, PI);
}

return st;

}

float drawCircle(vec2 st, vec2 position, float size){

float result = distance(st, position);
result = 1.0 - step (size, result);

return result;

}

float drawRect(vec2 st, vec2 pos, vec2 size){
float result = 1.0;

//invert size so the size variables will control the size based on the white dimensions
vec2 border = (1.0-size)/2.0;

result = step(border.x + pos.x, st.x);
result *= step(border.x - pos.x, 1.0-st.x);
result *= step(border.y + pos.y, st.y);
result *= step(border.y - pos.y, 1.0-st.y);

return result;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;

vec3 color = vec3(0.0);

//scale coordinate system to see noise
vec2 pos = vec2(st.x*1.0 - sin(u_time*0.2), st.y*1.0 + cos(u_time*0.2));

//BACKGROUND
color.r = snoise(pos) * 0.5 + 0.5;
color.b = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
// color.r = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
// color.g = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
color.g = snoise(pos + vec2(u_time*0.1)) * 0.5 + 0.5;

//TILE and ROTATE
st *= vec2(0.5, 0.5);
st += rotate2D(st,PI*0.5);

//then rotate title patterns based on index/location
st = rotateTilePattern(st+0.25);

//CIRCLE SETUP
//Animated circle size with noise function, add "st" in vector with noise to create a dynamic shape
//create an offset in size and opacity for each subsequent circle
float circle = drawCircle(st, vec2(0.580,0.550), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 0.5 + 0.1)*1.0;
float circle2 = drawCircle(st, vec2(0.500,0.500), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 1.0 + 0.1)*0.75;
float circle3 = drawCircle(st, vec2(0.710,0.330), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 1.5 + 0.1)*0.5;

vec3 circleColor = vec3(0.005,0.005,0.005);

// circleColor.r = snoise(pos) * 0.5 + 0.5;
// circleColor.b = snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5;
// circleColor.g = snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5;

// circleColor.b *= (snoise(pos) * 0.5 + 0.5)*0.2;
// circleColor.b += (snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5)*0.2;
// circleColor.b += (snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5)*0.2;

//circle color normal black and white gradient
circleColor = vec3(snoise(pos) * 0.5 + 0.5)*0.2;
circleColor += vec3(snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5)*0.2;
circleColor += vec3(snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5)*0.2;

//RECTANGLE OVERLAY
//solid black outline
// float rectangle = drawRect(st, vec2(0.0), vec2(0.9)-0.1);

//low opacity outline
float rectangle = drawRect(st, vec2(0.0), vec2(0.6)-0.1);
rectangle -= drawRect(st, vec2(0.0), vec2(0.8)-0.1);

//full opactity fill of rectangle
// rectangle = drawRect(st, vec2(0.0), vec2(0.8)-0.1);

//MIX/LAYER CIRCLES
//second mix parameter controls color of shape (circle)
color = vec3(mix(color, circleColor, circle));
color = vec3(mix(color, circleColor, circle2));
color = vec3(mix(color, circleColor, circle3));

//second mix parameter controls brightness/opacity of rectangular overlay
color = vec3(mix(color, vec3(u_mouse.x/u_resolution.x), rectangle));

gl_FragColor = vec4(color,1.0);
}

&amp;amp;amp;nbsp;

```