Drag the mouse to interact with the canvas and press the space bar to toggle the cursor color.
xxxxxxxxxx
// Reaction-Diffusion © 2024-05-15 by Zaron Chen is licensed under the MIT License. See LICENSE for more details.
//
// Interaction
// - Mouse Drag: Interact with the canvas by dragging the mouse
// - Space Bar: Press the space bar to toggle between a black and white cursor
//
// References
// The implementation is based on these videos:
// - noones img - Reaction-diffusion in 20 seconds (Touchdesginer tutorial): https://www.youtube.com/watch?v=CzmRMKQBMSw
// - ArtOfSoulburn - Reaction Diffusion In Photoshop: https://www.youtube.com/watch?v=I6Vh_NOy70M
// - SkyBase - Tutorial: Reaction-Diffusion in Photoshop: https://vimeo.com/61154654
import { mountFlex } from "https://cdn.jsdelivr.net/npm/p5.flex@0.2.0/src/p5.flex.mjs"
import { BLUR, UNSHARP, VERT } from "./shader.js"
p5.disableFriendlyErrors = true
mountFlex(p5)
new p5((p) => {
const [WIDTH, HEIGHT] = [600, 600]
const PIXEL_DENSITY = 1
const TEXEL_SIZE = [1 / (WIDTH * PIXEL_DENSITY), 1 / (HEIGHT * PIXEL_DENSITY)]
const RENDERER = p.WEBGL
const MIN_SIDE = p.min(WIDTH, HEIGHT)
let cnv, gfx, img
let BlurPass, UnsharpPass
let CURSOR_COLOR = 255
p.preload = () => (img = p.loadImage("NoiseMono_2.png"))
p.setup = () => {
cnv = p.createCanvas(WIDTH, HEIGHT, RENDERER)
p.flex({ container: { padding: "20px" }, canvas: { fit: p.SCALE_DOWN } })
p.pixelDensity(PIXEL_DENSITY)
gfx = p.createGraphics(WIDTH, HEIGHT, p.WEBGL)
BlurPass = p.createShader(VERT, BLUR)
UnsharpPass = p.createShader(VERT, UNSHARP)
RENDERER === p.WEBGL && p.rectMode(p.CENTER)
RENDERER === p.WEBGL && p.imageMode(p.CENTER)
p.background(0)
p.noStroke()
gfx.noStroke()
p.image(img, 0, 0, WIDTH, HEIGHT)
for (let _ = 0; _ < 3; _++) p.draw()
}
p.draw = () => {
Cursor()
Border()
ReactionDiffusion()
}
p.keyPressed = () => p.key === " " && (CURSOR_COLOR = CURSOR_COLOR ? 0 : 255)
const Cursor = () => {
p.push()
RENDERER === p.WEBGL && p.translate(-WIDTH / 2, -HEIGHT / 2)
p.fill(CURSOR_COLOR)
p.mouseIsPressed && p.circle(p.mouseX, p.mouseY, MIN_SIDE / 6)
p.pop()
}
const Border = () => {
p.push()
p.noFill()
p.stroke(255)
p.strokeWeight(MIN_SIDE / 6)
p.rect(0, 0, WIDTH, HEIGHT)
p.pop()
}
const ReactionDiffusion = () => {
gfx.shader(BlurPass)
BlurPass.setUniform("texelSize", TEXEL_SIZE)
BlurPass.setUniform("tex0", cnv)
BlurPass.setUniform("direction", [1, 0])
gfx.quad(-1, 1, 1, 1, 1, -1, -1, -1)
gfx.shader(BlurPass)
BlurPass.setUniform("texelSize", TEXEL_SIZE)
BlurPass.setUniform("tex0", gfx)
BlurPass.setUniform("direction", [0, 1])
gfx.quad(-1, 1, 1, 1, 1, -1, -1, -1)
gfx.shader(UnsharpPass)
UnsharpPass.setUniform("texelSize", TEXEL_SIZE)
UnsharpPass.setUniform("tex0", gfx)
gfx.quad(-1, 1, 1, 1, 1, -1, -1, -1)
p.image(gfx, 0, 0)
}
})