let displaceColorsSrc = `
const int NUM_ZOOM_SAMPLES = 20;
vec3 p3 = fract(vec3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
return noise(vec2(p, 0.));
vec4 color = vec4(0., 0., 0., 0.);
vec2 zoomedCoord = 1. - vTexCoord;
vec2 blurDirection = -zoomedCoord + 0.5;
for (int i = 0; i < NUM_ZOOM_SAMPLES; i++) {
vec2 noiseSeed = gl_FragCoord.xy * 1.1 + float(i) * 2.;
vec2 coordR = zoomedCoord + blurDirection * mix(0.95, 1., fract(12.3*noise(noiseSeed))) * 0.95 * blurScale;
vec2 coordG = zoomedCoord + blurDirection * mix(0.95, 1., fract(12.3*noise(noiseSeed + 4.56))) * blurScale;
vec2 coordB = zoomedCoord + blurDirection * mix(0.95, 1., fract(12.3*noise(noiseSeed + 7.89))) * 1.05 * blurScale;
texture2D(tex0, coordR).x,
texture2D(tex0, coordG).y,
texture2D(tex0, coordB).z,
texture2D(tex0, coordB).w
gl_FragColor = color / float(NUM_ZOOM_SAMPLES);
drawingContext.clear(drawingContext.DEPTH_BUFFER_BIT)
env = loadImage('outdoor_spheremap_small.jpg')
font = loadFont('https://fonts.gstatic.com/s/inter/v3/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuGKYMZhrib2Bg-4.ttf')
docs1 = loadImage('describe.png')
docs2 = loadImage('createVideo.png')
createCanvas(400, 400, WEBGL)
setAttributes({ antialias: true })
cnv = createGraphics(width, height)
displaceColors = cnv.createFilterShader(displaceColorsSrc)
image(env, 0, 0, width, height, 0, 0, env.width, env.height, COVER)
canvasStartCoord = createVector(0, 0)
{ pt: createVector(250, 250) },
{ pt: canvasStartCoord },
path: createBezierPath(smoothPoints([
{ pt: canvasStartCoord },
...times(15).map(() => ({
pt: createVector(random(-200, 200), random(-200, 200)),
function drawMouse(x, y) {
const polarVertex = (theta, r) => {
vertex(r * cos(theta), r * sin(theta))
const aMid = (aLeft + aRight) / 2
const aMidL = aMid + PI * 0.03
const aMidL2 = aMid + PI * 0.017
const aMidR = aMid - PI * 0.03
const aMidR2 = aMid - PI * 0.017
const t = frameCount / 60 * 1000
const secondsPerScene = 4
const scene = floor(t / (secondsPerScene * 1000)) % 5
const frame = (frameCount % (secondsPerScene * 60))
const idx = frame < mousePaths[0].to ? 0 : 1
const pos = mousePaths[idx].path.getPointAtLength(
mousePaths[idx].path.getTotalLength() * easeInOutCubic(
map(frame, mousePaths[idx].from, mousePaths[idx].to, 0, 1, true)
const txtPos = idx === 0 ? canvasStartCoord : pos
textAlign(CENTER, CENTER)
text('draggable()', txtPos.x, txtPos.y)
} else if (scene === 1) {
translate(0, -height*0.05)
rotateY(sin(frameCount/20) * PI * 0.2)
rotateX(sin(frameCount/35) * PI * 0.1)
text('imageLight()', -width/2 + 20, height/2 - 20)
} else if (scene === 2) {
cnv.background('#8eb7f5')
particles = times(40).map(() => {
c: lerpColor(color('#e35944'), color('#e3ae44'), random()),
for (const particle of particles) {
particle.x += particle.vx
particle.y += particle.vy
if (particle.x-particle.r < 0 || particle.x+particle.r > width) {
if (particle.y-particle.r < 0 || particle.y+particle.r > height) {
cnv.circle(particle.x, particle.y, particle.r)
cnv.textAlign(CENTER, CENTER)
cnv.text('Custom filters\nin 2D mode', width/2, height/2)
cnv.filter(displaceColors)
} else if (scene === 3) {
const progress = frame / (secondsPerScene * 60)
const s = width / docs1.width
const s2 = width / docs2.width
image(docs1, -width/2, -height/2 - (progress*(docs1.height*s - height)), docs1.width*s, docs1.height*s)
tint(255, map(progress, 0.4, 0.6, 0, 255, true))
image(docs2, -width/2, -height/2 - ((1-progress)*(docs2.height*s2 - height)), docs2.width*s2, docs2.height*s2)
textAlign(CENTER, BOTTOM)
text('Lots of reference updates', 0, height/2)
textAlign(CENTER, CENTER)
translate(width*0.4, -height*0.3)
} else if (scene === 4) {
textAlign(CENTER, CENTER)
text('p5*js 1.9.0', 0, 0)
function smoothPoints(points) {
return points.map((point, i) => {
if (i === 0 || i === points.length - 1) {
const tangent = points[i+1].pt.copy().sub(points[i-1].pt).div(2.5)
left: point.pt.copy().sub(tangent),
right: point.pt.copy().add(tangent),
const easeInOutCubic = t => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1
const easeOutElastic = t => {
const c4 = (2 * Math.PI) / 3
: Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1