)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Raphaël Easing Equations How To

  1. const { pow, PI } = Math;
  2.  
  3. // mostly unedited code from Raphaël
  4. var ef = {
  5.   linear: function(n) {
  6.     return n;
  7.   },
  8.   '<': function(n) {
  9.     return pow(n, 1.7);
  10.   },
  11.   '>': function(n) {
  12.     return pow(n, 0.48);
  13.   },
  14.   '<>': function(n) {
  15.     var q = 0.48 - n / 1.04,
  16.       Q = Math.sqrt(0.1734 + q * q),
  17.       x = Q - q,
  18.       X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
  19.       y = -Q - q,
  20.       Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
  21.       t = X + Y + 0.5;
  22.     return (1 - t) * 3 * t * t + t * t * t;
  23.   },
  24.   backIn: function(n) {
  25.     var s = 1.70158;
  26.     return n * n * ((s + 1) * n - s);
  27.   },
  28.   backOut: function(n) {
  29.     n = n - 1;
  30.     var s = 1.70158;
  31.     return n * n * ((s + 1) * n + s) + 1;
  32.   },
  33.   elastic: function(n) {
  34.     if (n == !!n) {
  35.       return n;
  36.     }
  37.     return pow(2, -10 * n) * Math.sin(((n - 0.075) * (2 * PI)) / 0.3) + 1;
  38.   },
  39.   bounce: function(n) {
  40.     var s = 7.5625,
  41.       p = 2.75,
  42.       l;
  43.     if (n < 1 / p) {
  44.       l = s * n * n;
  45.     } else {
  46.       if (n < 2 / p) {
  47.         n -= 1.5 / p;
  48.         l = s * n * n + 0.75;
  49.       } else {
  50.         if (n < 2.5 / p) {
  51.           n -= 2.25 / p;
  52.           l = s * n * n + 0.9375;
  53.         } else {
  54.           n -= 2.625 / p;
  55.           l = s * n * n + 0.984375;
  56.         }
  57.       }
  58.     }
  59.     return l;
  60.   }
  61. };
  62. ef.easeIn = ef['ease-in'] = ef['<'];
  63. ef.easeOut = ef['ease-out'] = ef['>'];
  64. ef.easeInOut = ef['ease-in-out'] = ef['<>'];
  65. ef['back-in'] = ef.backIn;
  66. ef['back-out'] = ef.backOut;
  67.  
  68. // create a dot
  69. function dot(x, y, radius, color) {
  70.   const el = document.createElement('div');
  71.   const size = `${radius * 2}px`;
  72.   Object.assign(el.style, {
  73.     position: 'absolute',
  74.     left: `${x}px`,
  75.     top: `${y}px`,
  76.     width: size,
  77.     height: size,
  78.     transform: `translate(${-radius}px, ${-radius}px)`,
  79.     borderRadius: '50%',
  80.     background: color
  81.   });
  82.   el.classList.add('dot');
  83.   document.body.appendChild(el);
  84.   return el;
  85. }
  86.  
  87. const elA = dot(0, 40, 30, 'red');
  88. const elB = dot(0, 110, 30, 'blue');
  89. const elC = dot(0, 160, 20, 'green');
  90.  
  91. // how to use the easing equations:
  92. let t = 0;
  93.  
  94. let start = Date.now();
  95. let time = 0;
  96. let duration = 2; // 2 seconds
  97. function loop() {
  98.   // frame based
  99.   elA.style.left = `${ef.elastic(t) * 50}%`;
  100.   t += 0.005;
  101.  
  102.   // time based
  103.   if (time <= duration) {
  104.     time = (Date.now() - start) / 1000;
  105.     const param = time / duration;
  106.     elB.style.left = `${ef.elastic(param) * 50}%`;
  107.  
  108.     // green bounce example
  109.     elC.style.left = `${ef.bounce(param) * 50}%`;
  110.   }
  111.  
  112.   requestAnimationFrame(loop);
  113. }
  114. loop();

I realized it might not be obvious how to use Raphaël’s easing equations. So I speed coded this example.

If you’d like to learn more about this kind of thing gsap is a great place to start… it is amazing… I highly recommend browsing the source.

Polar Plots

  1. const Pnt = (x, y, p = { x, y }) => (
  2.   p.add = o => (p.x += o.x, p.y += o.y, p), p
  3. );
  4. Pnt.polar = (rad, t) => Pnt(rad * Math.cos(t), rad * Math.sin(t));
  5.  
  6. const pnts = {};
  7. let index = -1;
  8. const polar = (inc, rad) => {
  9.   index++;
  10.   if (!pnts[index]) pnts[index] = 0;
  11.   return Pnt.polar(rad, (pnts[index] += inc));
  12. };
  13.  
  14. let d = document;
  15. let b = d.body;
  16. with (b.appendChild(
  17.   Object.assign(d.createElement`canvas`, {
  18.     width: 600,
  19.     height: 500,
  20.   })
  21. ).getContext`2d`) {
  22.   canvas.style.transformOrigin = "0 0";
  23.   canvas.style.transform = "scale(.6)";
  24.  
  25.   let p0 = Pnt(80, 100);
  26.   let p1 = Pnt(270, 100);
  27.   let p2 = Pnt(480, 40);
  28.   let p3 = Pnt(170, 180);
  29.   let p4 = Pnt(430, 300);
  30.  
  31.   fillStyle = "black";
  32.  
  33.   function loop() {
  34.     for (let i = 0; i < 20; i++) {
  35.       index = -1;
  36.  
  37.       p0.add(polar(0.2, 4).add(polar(-0.4, 2).add(polar(0.05, 1))));
  38.       fillRect(p0.x, p0.y, 1, 1);
  39.  
  40.       p1.add(
  41.         polar(0.1, 2).add(
  42.           polar(-0.2, 2).add(polar(0.03, 1).add(polar(-0.01, 0.5)))
  43.         )
  44.       );
  45.       fillRect(p1.x, p1.y, 1, 1);
  46.  
  47.       p2.add(polar(0.08, 3).add(polar(-0.2, -12).add(polar(2, 10))));
  48.       fillRect(p2.x, p2.y, 1, 1);
  49.  
  50.       p3.add(polar(0.08, 7).add(polar(-0.2, -12).add(polar(2, 11))));
  51.       fillRect(p3.x, p3.y, 1, 1);
  52.  
  53.       p4 = p4.add(polar(0.025, 2).add(polar(-0.05, 1)));
  54.       fillRect(p4.x, p4.y, 1, 1);
  55.     }
  56.     requestAnimationFrame(loop);
  57.   }
  58.  
  59.   loop();
  60. }

Some polar plots…

WebGL Particles in Sphere

  1. (() => {
  2.   const m = new Float32Array([
  3.     0, 0, 0, 0, 
  4.     0, 0, 0, 0, 
  5.     0, 0, 0, 0, 
  6.     0, 0, 0, 0])
  7.  
  8.   const pointSize = Math.max(Math.min(30, ~~(innerWidth / 70)), 3)
  9.  
  10.   const vert = `
  11.     attribute vec3 vec;
  12.     uniform mat4 mat;
  13.     void main(void) {
  14.       gl_Position = mat * vec4(vec, 1.0);
  15.       gl_PointSize = ${pointSize}.0;
  16.     }
  17.   `
  18.  
  19.   const frag = `
  20.     void main(void) {
  21.       gl_FragColor = vec4(1., 1., 1., .25);
  22.     }
  23.   `
  24.  
  25.   document.body.style.background = '#232323'
  26.   const gl = document.body
  27.     .appendChild(document.createElement('canvas'))
  28.     .getContext('webgl', {
  29.       preserveDrawingBuffer: true,
  30.       powerPreference: 'high-performance'
  31.     })
  32.  
  33.   Object.assign(gl.canvas.style, {
  34.     position: 'absolute',
  35.     left: '50%',
  36.     top: '50%',
  37.     transform: 'translate(-50%, -50%)',
  38.     outline: '1px solid gray'
  39.   })
  40.  
  41.   with (gl) {
  42.     const NUM = 4000
  43.     const radius = 0.7
  44.     const verts = []
  45.  
  46.     for (let i = 0; i < NUM; i += 3) {
  47.       let xp = Math.random() * 2 - 1
  48.       let yp = Math.random() * 2 - 1
  49.       let zp = Math.random() * 2 - 1
  50.       let dist = Math.sqrt(xp * xp + yp * yp + zp * zp)
  51.       // normalize and scale x,y,z
  52.       verts[i] = (xp / dist) * radius
  53.       verts[i + 1] = (yp / dist) * radius
  54.       verts[i + 2] = (zp / dist) * radius
  55.  
  56.     }
  57.     const overts = verts.concat()
  58.     const leng = verts.length / 3
  59.  
  60.     bindBuffer(ARRAY_BUFFER, createBuffer())
  61.     bufferData(ARRAY_BUFFER, new Float32Array(verts), STATIC_DRAW)
  62.  
  63.     const vs = createShader(VERTEX_SHADER)
  64.     shaderSource(vs, vert)
  65.     compileShader(vs)
  66.  
  67.     const fs = createShader(FRAGMENT_SHADER)
  68.     const sp = createProgram()
  69.  
  70.     shaderSource(fs, frag)
  71.     compileShader(fs)
  72.     attachShader(sp, vs)
  73.     attachShader(sp, fs)
  74.     linkProgram(sp)
  75.     useProgram(sp)
  76.  
  77.     const vec = getAttribLocation(sp, 'vec')
  78.     vertexAttribPointer(vec, 3, FLOAT, false, 0, 0)
  79.     enableVertexAttribArray(vec)
  80.  
  81.     const matLoc = getUniformLocation(sp, 'mat')
  82.  
  83.     function rot(x, y, z) {
  84.       // https://wikimedia.org/api/rest_v1/media/math/render/svg/a8e16f4967571b7a572d1a19f3f6468512f9843e
  85.  
  86.       const sinA = Math.sin(x)
  87.       const cosA = Math.cos(x)
  88.       const sinB = Math.sin(y)
  89.       const cosB = Math.cos(y)
  90.       const sinY = Math.sin(z)
  91.       const cosY = Math.cos(z)
  92.  
  93.       m[0] = cosA * cosB
  94.       m[1] = cosA * sinB * sinY - sinA * cosY
  95.       m[2] = cosA * sinB * cosY + sinA * sinY
  96.       m[3] = 0
  97.  
  98.       m[4] = sinA * cosB
  99.       m[5] = sinA * sinB * sinY + cosA * cosY
  100.       m[6] = sinA * sinB * cosY - cosA * sinY
  101.       m[7] = 0
  102.  
  103.       m[8] = -sinB
  104.       m[9] = cosB * sinY
  105.       m[10] = cosB * cosY
  106.       m[11] = m[12] = m[13] = 0
  107.       m[15] = 1
  108.  
  109.       uniformMatrix4fv(matLoc, false, m)
  110.     }
  111.  
  112.     onresize = () => {
  113.       const { canvas } = gl
  114.       const size = Math.min(innerWidth, innerHeight) - 20
  115.       canvas.width = canvas.height = size
  116.       viewport(0, 0, size, size)
  117.     }
  118.  
  119.     onresize()
  120.  
  121.     let rx = 0,
  122.       ry = 0,
  123.       rz = 0
  124.     let t = 0
  125.  
  126.     function loop() {
  127.       rx += 0.01
  128.       ry += 0.01
  129.       rot(rx, ry, rz)
  130.  
  131.       disable(DEPTH_TEST)
  132.       enable(BLEND)
  133.       blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
  134.  
  135.       clearColor(0, 0, 0, 1)
  136.  
  137.       clear(COLOR_BUFFER_BIT)
  138.  
  139.       for (let i = 0; i < verts.length; i += 3) {
  140.         let tof = i * 0.001 + t;
  141.         verts[i] = Math.sin(tof) * overts[i]
  142.         verts[i + 1] = Math.sin(tof) * overts[i + 1]
  143.         verts[i + 2] = Math.sin(tof) * overts[i + 2]
  144.       }
  145.  
  146.       t += 0.01
  147.  
  148.       bufferSubData(ARRAY_BUFFER, 0, new Float32Array(verts))
  149.  
  150.       drawArrays(POINTS, 0, leng)
  151.       window.requestAnimationFrame(loop)
  152.     }
  153.     loop()
  154.   }
  155. })()

Playing around with animating points…

WebGL Points and Rotation

  1. (() => {
  2.   const m = new Float32Array([
  3.     0, 0, 0, 0, 
  4.     0, 0, 0, 0, 
  5.     0, 0, 0, 0, 
  6.     0, 0, 0, 0
  7.   ])
  8.  
  9.   const pointSize = Math.max(Math.min(10, ~~(innerWidth / 70)), 3);
  10.  
  11.   const vert = `
  12.     attribute vec3 vec;
  13.     uniform mat4 mat;
  14.     void main(void) {
  15.       gl_Position = mat * vec4(vec, 1.);
  16.       gl_PointSize = ${pointSize}.;
  17.     }
  18.   `
  19.  
  20.   const frag = `
  21.     void main(void) {
  22.       gl_FragColor = vec4(1., 1., 1., .4);
  23.     }
  24.   `
  25.  
  26.   document.body.style.background = '#333'
  27.   const gl = document.body
  28.     .appendChild(document.createElement('canvas'))
  29.     .getContext('webgl')
  30.  
  31.   Object.assign(gl.canvas.style, {
  32.     position: 'absolute',
  33.     left: '50%',
  34.     top: '50%',
  35.     transform: 'translate(-50%, -50%)',
  36.     outline: '1px solid gray'
  37.   })
  38.  
  39.   with (gl) {
  40.     const NUM = 600
  41.     const verts = []
  42.  
  43.     for (let i = 0; i < NUM; i++) {
  44.       verts.push(
  45.         Math.random() * 1 - 0.5,
  46.         Math.random() * 1 - 0.5,
  47.         Math.random() * 1 - 0.5
  48.       )
  49.     }
  50.  
  51.     const leng = verts.length / 3
  52.     bindBuffer(ARRAY_BUFFER, createBuffer())
  53.     bufferData(ARRAY_BUFFER, new Float32Array(verts), STATIC_DRAW)
  54.  
  55.     const vs = createShader(VERTEX_SHADER)
  56.     shaderSource(vs, vert)
  57.     compileShader(vs)
  58.  
  59.     const fs = createShader(FRAGMENT_SHADER)
  60.     const sp = createProgram()
  61.  
  62.     shaderSource(fs, frag)
  63.     compileShader(fs)
  64.     attachShader(sp, vs)
  65.     attachShader(sp, fs)
  66.     linkProgram(sp)
  67.     useProgram(sp)
  68.  
  69.     const vec = getAttribLocation(sp, 'vec')
  70.     vertexAttribPointer(vec, 3, FLOAT, false, 0, 0)
  71.     enableVertexAttribArray(vec)
  72.  
  73.     const matLoc = getUniformLocation(sp, 'mat')
  74.  
  75.     function rot(x, y, z) {
  76.       // https://wikimedia.org/api/rest_v1/media/math/render/svg/a8e16f4967571b7a572d1a19f3f6468512f9843e
  77.  
  78.       const sinA = Math.sin(x)
  79.       const cosA = Math.cos(x)
  80.       const sinB = Math.sin(y)
  81.       const cosB = Math.cos(y)
  82.       const sinY = Math.sin(z)
  83.       const cosY = Math.cos(z)
  84.  
  85.       m[0] = cosA * cosB
  86.       m[1] = cosA * sinB * sinY - sinA * cosY
  87.       m[2] = cosA * sinB * cosY + sinA * sinY
  88.       m[3] = 0
  89.  
  90.       m[4] = sinA * cosB
  91.       m[5] = sinA * sinB * sinY + cosA * cosY
  92.       m[6] = sinA * sinB * cosY - cosA * sinY
  93.       m[7] = 0
  94.  
  95.       m[8] = -sinB
  96.       m[9] = cosB * sinY
  97.       m[10] = cosB * cosY
  98.       m[11] = m[12] = m[13] = 0
  99.       m[15] = 1
  100.  
  101.       uniformMatrix4fv(matLoc, false, m)
  102.     }
  103.  
  104.     onresize = () => {
  105.       const { canvas } = gl
  106.       const size = Math.min(innerWidth, innerHeight) - 20
  107.       canvas.width = canvas.height = size
  108.       viewport(0, 0, size, size)
  109.     }
  110.  
  111.     onresize()
  112.  
  113.     let ry = 0, rz = 0
  114.  
  115.     disable(DEPTH_TEST)
  116.     enable(BLEND)
  117.     blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
  118.  
  119.     function loop() {
  120.       rot(0, ry -= 0.03, rz += 0.001)
  121.  
  122.       clearColor(0, 0, 0, 1)
  123.       clear(COLOR_BUFFER_BIT)
  124.       drawArrays(POINTS, 0, leng)
  125.       window.requestAnimationFrame(loop)
  126.     }
  127.     loop()
  128.   }
  129. })()

Some WebGL points with rotation… I couldn’t resist using with here…

Gray Gradient Texture

  1. function rect(x1, y1, x2, y2, col, blur = 0.1) {
  2.   const dx = x1 - x2;
  3.   const dy = y1 - y2;
  4.   const dist = Math.sqrt(dx * dx + dy * dy);
  5.   return `radial-gradient(circle at ${x1}% ${y1}%, ${col} 0, ${col} ${dist}%, transparent ${dist +
  6.     blur}%)`;
  7. }
  8. const blends = 'multiply,screen,overlay,darken,lighten,color-dodge,color-burn,hard-light,soft-light,difference,exclusion,hue'.split(
  9.   ','
  10. );
  11. const cols = ['black', 'white'];
  12.  
  13. function gen() {
  14.   [...document.querySelectorAll('div')].forEach(d =>
  15.     d.parentNode.removeChild(d)
  16.   );
  17.   for (let j = 0; j < 4; j++) {
  18.     const rects = [];
  19.     for (let i = 0; i < 10; i++) {
  20.       const x = Math.random() * 100;
  21.       const y = Math.random() * 100;
  22.       const s = Math.random() * Math.random() * Math.random() * 30 + 3;
  23.       const col = cols[~~(Math.random() * cols.length)];
  24.       rects.push(rect(x, y, x + s, y + s, col, Math.random() * 10));
  25.     }
  26.     const el = document.body.appendChild(document.createElement('div'));
  27.     el.style.backgroundImage = rects.join(', ');
  28.     el.style.mixBlendMode = blends[~~(Math.random() * blends.length)];
  29.   }
  30. }
  31. gen();
  32.  
  33. document.body.innerHTML += `
  34.   <button id="regen">Regenerate</button>
  35.   <style>
  36.     body, html {
  37.       height: 100%;
  38.       background: #ccc;
  39.       margin: 0;
  40.       background-repeat: no-repeat;
  41.       width: 100%;
  42.     }
  43.     div {
  44.       position: absolute;
  45.       top: 0; left: 0;
  46.       width: 100%;
  47.       height: 100%;
  48.     }
  49.     #regen {
  50.       position: absolute;
  51.       width: 100px;
  52.       height: 30px;
  53.       background: #ccc;
  54.       border: 1px solid white;
  55.       margin: 1em;
  56.       cursor: pointer;
  57.       transition: all 250ms ease-out;
  58.       z-index: 999;
  59.     }
  60.     #regen:hover { background: #333; color: white; }
  61.   </style>
  62. `;
  63.  
  64. regen.onclick = gen;

Playing around some more with lots of linear gradients.

snippet.zone ~ 2021-23 /// {s/z}