The prompt that made it
as published# SIMPLEX — DITHERING SHADER COMPONENT INTEGRATION
YOU ARE GIVEN A TASK TO INTEGRATE AN EXISTING REACT COMPONENT IN THE CODEBASE
THE CODEBASE SHOULD SUPPORT:
- SHADCN PROJECT STRUCTURE
- TAILWIND CSS
- TYPESCRIPT
IF IT DOESN'T, PROVIDE INSTRUCTIONS ON HOW TO SETUP PROJECT VIA SHADCN CLI, INSTALL TAILWIND OR TYPESCRIPT.
DETERMINE THE DEFAULT PATH FOR COMPONENTS AND STYLES.
IF DEFAULT PATH FOR COMPONENTS IS NOT /COMPONENTS/UI, PROVIDE INSTRUCTIONS ON WHY IT'S IMPORTANT TO CREATE THIS FOLDER
COPY-PASTE THIS COMPONENT TO /COMPONENTS/UI FOLDER:
```tsx
simplex.tsx
import { cn } from "@/lib/utils";
import { useState } from "react";
export const Component = () => {
const [count, setCount] = useState(0);
return (
<div className={cn("flex flex-col items-center gap-4 p-4 rounded-lg")}>
<h1 className="text-2xl font-bold mb-2">Component Example</h1>
<h2 className="text-xl font-semibold">{count}</h2>
<div className="flex gap-2">
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
</div>
</div>
);
};
demo.tsx
import { DitheringShader } from "@/components/ui/dithering-shader";
export default function DemoOne() {
return (
<div className="relative flex h-full w-full flex-col items-center justify-center overflow-hidden">
<DitheringShader
shape="ripple"
type="2x2"
colorBack="#330000"
colorFront="#ffff00"
pxSize={2}
speed={1.2}
/>
<span className="pointer-events-none z-10 text-center text-7xl leading-none absolute font-semibold text-white tracking-tighter whitespace-pre-wrap">
Simplex
</span>
</div>
)
}
```
COPY-PASTE THESE FILES FOR DEPENDENCIES:
```tsx
designali-in/dithering-shader
"use client"
import type React from "react"
import { useEffect, useRef } from "react"
// GLSL utility functions
const declarePI = `
#define TWO_PI 6.28318530718
#define PI 3.14159265358979323846
`
const proceduralHash11 = `
float hash11(float p) {
p = fract(p * 0.3183099) + 0.1;
p *= p + 19.19;
return fract(p * p);
}
`
const proceduralHash21 = `
float hash21(vec2 p) {
p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
`
const simplexNoise = `
vec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }
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 > 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);
}
`
// Vertex shader
const vertexShaderSource = `#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_position;
void main() {
gl_Position = a_position;
}
`
// Fragment shader
const fragmentShaderSource = `#version 300 es
precision mediump float;
uniform float u_time;
uniform vec2 u_resolution;
uniform vec4 u_colorBack;
uniform vec4 u_colorFront;
uniform float u_shape;
uniform float u_type;
uniform float u_pxSize;
out vec4 fragColor;
${simplexNoise}
${declarePI}
${proceduralHash11}
${proceduralHash21}
float getSimplexNoise(vec2 uv, float t) {
float noise = .5 * snoise(uv - vec2(0., .3 * t));
noise += .5 * snoise(2. * uv + vec2(0., .32 * t));
return noise;
}
const int bayer2x2[4] = int[4](0, 2, 3, 1);
const int bayer4x4[16] = int[16](
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
);
const int bayer8x8[64] = int[64](
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
);
float getBayerValue(vec2 uv, int size) {
ivec2 pos = ivec2(mod(uv, float(size)));
int index = pos.y * size + pos.x;
if (size == 2) {
return float(bayer2x2[index]) / 4.0;
} else if (size == 4) {
return float(bayer4x4[index]) / 16.0;
} else if (size == 8) {
return float(bayer8x8[index]) / 64.0;
}
return 0.0;
}
void main() {
float t = .5 * u_time;
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
uv -= .5;
// Apply pixelization
float pxSize = u_pxSize;
vec2 pxSizeUv = gl_FragCoord.xy;
pxSizeUv -= .5 * u_resolution;
pxSizeUv /= pxSize;
vec2 pixelizedUv = floor(pxSizeUv) * pxSize / u_resolution.xy;
pixelizedUv += .5;
pixelizedUv -= .5;
vec2 shape_uv = pixelizedUv;
vec2 dithering_uv = pxSizeUv;
vec2 ditheringNoise_uv = uv * u_resolution;
float shape = 0.;
if (u_shape < 1.5) {
// Simplex noise
shape_uv *= .001;
shape = 0.5 + 0.5 * getSimplexNoise(shape_uv, t);
shape = smoothstep(0.3, 0.9, shape);
} else if (u_shape < 2.5) {
// Warp
shape_uv *= .003;
for (float i = 1.0; i < 6.0; i++) {
shape_uv.x += 0.6 / i * cos(i * 2.5 * shape_uv.y + t);
shape_uv.y += 0.6 / i * cos(i * 1.5 * shape_uv.x + t);
}
shape = .15 / abs(sin(t - shape_uv.y - shape_uv.x));
shape = smoothstep(0.02, 1., shape);
} else if (u_shape < 3.5) {
// Dots
shape_uv *= .05;
float stripeIdx = floor(2. * shape_uv.x / TWO_PI);
float rand = hash11(stripeIdx * 10.);
rand = sign(rand - .5) * pow(.1 + abs(rand), .4);
shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);
shape = pow(abs(shape), 6.);
} else if (u_shape < 4.5) {
// Sine wave
shape_uv *= 4.;
float wave = cos(.5 * shape_uv.x - 2. * t) * sin(1.5 * shape_uv.x + t) * (.75 + .25 * cos(3. * t));
shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);
} else if (u_shape < 5.5) {
// Ripple
float dist = length(shape_uv);
float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;
shape = waves;
} else if (u_shape < 6.5) {
// Swirl
float l = length(shape_uv);
float angle = 6. * atan(shape_uv.y, shape_uv.x) + 4. * t;
float twist = 1.2;
float offset = pow(l, -twist) + angle / TWO_PI;
float mid = smoothstep(0., 1., pow(l, twist));
shape = mix(0., fract(offset), mid);
} else {
// Sphere
shape_uv *= 2.;
float d = 1. - pow(length(shape_uv), 2.);
vec3 pos = vec3(shape_uv, sqrt(d));
vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));
shape = .5 + .5 * dot(lightPos, pos);
shape *= step(0., d);
}
int type = int(floor(u_type));
float dithering = 0.0;
switch (type) {
case 1: {
dithering = step(hash21(ditheringNoise_uv), shape);
} break;
case 2:
dithering = getBayerValue(dithering_uv, 2);
break;
case 3:
dithering = getBayerValue(dithering_uv, 4);
break;
default:
dithering = getBayerValue(dithering_uv, 8);
break;
}
dithering -= .5;
float res = step(.5, shape + dithering);
vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
float fgOpacity = u_colorFront.a;
vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
float bgOpacity = u_colorBack.a;
vec3 color = fgColor * res;
float opacity = fgOpacity * res;
color += bgColor * (1. - opacity);
opacity += bgOpacity * (1. - opacity);
fragColor = vec4(color, opacity);
}
`
// Shape and type enums
export const DitheringShapes = {
simplex: 1,
warp: 2,
dots: 3,
wave: 4,
ripple: 5,
swirl: 6,
sphere: 7,
} as const
export const DitheringTypes = {
random: 1,
"2x2": 2,
"4x4": 3,
"8x8": 4,
} as const
export type DitheringShape = keyof typeof DitheringShapes
export type DitheringType = keyof typeof DitheringTypes
interface DitheringShaderProps {
width?: number
height?: number
colorBack?: string
colorFront?: string
shape?: DitheringShape
type?: DitheringType
pxSize?: number
speed?: number
className?: string
style?: React.CSSProperties
}
function hexToRgba(hex: string): [number, number, number, number] {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
if (!result) return [0, 0, 0, 1]
return [
Number.parseInt(result[1], 16) / 255,
Number.parseInt(result[2], 16) / 255,
Number.parseInt(result[3], 16) / 255,
1,
]
}
function createShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {
const shader = gl.createShader(type)
if (!shader) return null
gl.shaderSource(shader, source)
gl.compileShader(shader)
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader))
gl.deleteShader(shader)
return null
}
return shader
}
function createProgram(
gl: WebGL2RenderingContext,
vertexShaderSource: string,
fragmentShaderSource: string,
): WebGLProgram | null {
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource)
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource)
if (!vertexShader || !fragmentShader) return null
const program = gl.createProgram()
if (!program) return null
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("Unable to initialize the shader program: " + gl.getProgramInfoLog(program))
gl.deleteProgram(program)
return null
}
return program
}
export function DitheringShader({
width = 800,
height = 800,
colorBack = "#000000",
colorFront = "#ffffff",
shape = "simplex",
type = "8x8",
pxSize = 4,
speed = 1,
className = "",
style = {},
}: DitheringShaderProps) {
const canvasRef = useRef<HTMLCanvasElement>(null)
const animationRef = useRef<number>()
const programRef = useRef<WebGLProgram | null>(null)
const glRef = useRef<WebGL2RenderingContext | null>(null)
const uniformLocationsRef = useRef<Record<string, WebGLUniformLocation | null>>({})
const startTimeRef = useRef<number>(Date.now())
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const gl = canvas.getContext("webgl2")
if (!gl) {
console.error("WebGL2 not supported")
return
}
glRef.current = gl
// Create shader program
const program = createProgram(gl, vertexShaderSource, fragmentShaderSource)
if (!program) return
programRef.current = program
// Get uniform locations
uniformLocationsRef.current = {
u_time: gl.getUniformLocation(program, "u_time"),
u_resolution: gl.getUniformLocation(program, "u_resolution"),
u_colorBack: gl.getUniformLocation(program, "u_colorBack"),
u_colorFront: gl.getUniformLocation(program, "u_colorFront"),
u_shape: gl.getUniformLocation(program, "u_shape"),
u_type: gl.getUniformLocation(program, "u_type"),
u_pxSize: gl.getUniformLocation(program, "u_pxSize"),
}
// Set up position attribute
const positionAttributeLocation = gl.getAttribLocation(program, "a_position")
const positionBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)
gl.enableVertexAttribArray(positionAttributeLocation)
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0)
// Set canvas size
canvas.width = width
canvas.height = height
gl.viewport(0, 0, width, height)
// Animation loop
const render = () => {
const currentTime = (Date.now() - startTimeRef.current) * 0.001 * speed
const context = glRef.current
const shaderProgram = programRef.current
if (!context || !shaderProgram) return
context.clear(context.COLOR_BUFFER_BIT)
context["useProgram"](shaderProgram)
// Set uniforms
const locations = uniformLocationsRef.current
if (locations.u_time) context.uniform1f(locations.u_time, currentTime)
if (locations.u_resolution) context.uniform2f(locations.u_resolution, width, height)
if (locations.u_colorBack) context.uniform4fv(locations.u_colorBack, hexToRgba(colorBack))
if (locations.u_colorFront) context.uniform4fv(locations.u_colorFront, hexToRgba(colorFront))
if (locations.u_shape) context.uniform1f(locations.u_shape, DitheringShapes[shape])
if (locations.u_type) context.uniform1f(locations.u_type, DitheringTypes[type])
if (locations.u_pxSize) context.uniform1f(locations.u_pxSize, pxSize)
context.drawArrays(context.TRIANGLES, 0, 6)
if (speed !== 0) {
animationRef.current = requestAnimationFrame(render)
}
}
const startAnimation = () => {
if (speed !== 0) {
animationRef.current = requestAnimationFrame(render)
}
}
startAnimation()
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current)
}
if (glRef.current && programRef.current) {
glRef.current.deleteProgram(programRef.current)
}
}
}, [width, height, colorBack, colorFront, shape, type, pxSize, speed])
return (
<div
className={className}
style={{
position: "relative",
width,
height,
...style,
}}
>
<canvas
ref={canvasRef}
style={{
display: "block",
width: "100%",
height: "100%",
}}
/>
</div>
)
}
```
## IMPLEMENTATION GUIDELINES
1. ANALYZE THE COMPONENT STRUCTURE AND IDENTIFY ALL REQUIRED DEPENDENCIES
2. REVIEW THE COMPONENT'S ARGUMENS AND STATE
3. IDENTIFY ANY REQUIRED CONTEXT PROVIDERS OR HOOKS AND INSTALL THEM
4. QUESTIONS TO ASK
- WHAT DATA/PROPS WILL BE PASSED TO THIS COMPONENT?
- ARE THERE ANY SPECIFIC STATE MANAGEMENT REQUIREMENTS?
- ARE THERE ANY REQUIRED ASSETS (IMAGES, ICONS, ETC.)?
- WHAT IS THE EXPECTED RESPONSIVE BEHAVIOR?
- WHAT IS THE BEST PLACE TO USE THIS COMPONENT IN THE APP?
## STEPS TO INTEGRATE
0. COPY PASTE ALL THE CODE ABOVE IN THE CORRECT DIRECTORIES
1. INSTALL EXTERNAL DEPENDENCIES
2. FILL IMAGE ASSETS WITH UNSPLASH STOCK IMAGES YOU KNOW EXIST
3. USE LUCIDE-REACT ICONS FOR SVGS OR LOGOS IF COMPONENT REQUIRES THEMAdds a render step. Works best with the HyperFrames or Remotion skills installed. Free, no sign-up.
Prompt by @pulkitxm. Prompts belong to their creators.