Skip to content

Instantly share code, notes, and snippets.

@ultrox
Last active December 31, 2024 15:17
Show Gist options
  • Save ultrox/9fd8be5f05cb8dbf13fd27e311224dc3 to your computer and use it in GitHub Desktop.
Save ultrox/9fd8be5f05cb8dbf13fd27e311224dc3 to your computer and use it in GitHub Desktop.
Lerp
/**
* Linearly interpolates between two values (`start` and `end`) based on a given interpolation factor `t`.
*
* @param start - The starting value of the interpolation.
* @param end - The ending value of the interpolation.
* @param t - A factor between `0.0` and `1.0` that determines the weight of the `end` value.
* - `t = 0.0`: Returns the `start` value.
* - `t = 1.0`: Returns the `end` value.
* - `0.0 < t < 1.0`: Returns a value between `start` and `end`, weighted proportionally to `t`.
* - Values outside the range `[0.0, 1.0]` result in extrapolation beyond the `start` and `end` range.
*
* @returns The interpolated value between `start` and `end`.
*
* @example
* ```typescript
* const value = lerp(0, 10, 0.5); // Returns 5 (midpoint)
* const value2 = lerp(0, 10, 0.0); // Returns 0 (start)
* const value3 = lerp(0, 10, 1.0); // Returns 10 (end)
* const value4 = lerp(0, 10, 1.5); // Returns 15 (extrapolation)
* ```
*/
const lerp = (start: number, end: number, t: number): number => {
return start * (1 - t) + end * t;
};
// LERP as I lerend it first time.
// This is not the LERP you want to use, because
// how naive and 'dirty' it is.
// no containment, uses global state, lerp itself mutate stuff.
// raf not canceled, never clamped, etc
const circleEl = document.querySelector('.circle');
const currentPoint = { x: 0, y: 0 };
const targetPoint = { x: 0, y: 0 };
function lerp() {
currentPoint.x = currentPoint.x + (targetPoint.x - currentPoint.x) * 0.1;
currentPoint.y = currentPoint.y + (targetPoint.y - currentPoint.y) * 0.1;
circleEl.style.setProperty('--x', currentPoint.x);
circleEl.style.setProperty('--y', currentPoint.y);
requestAnimationFrame(lerp);
}
requestAnimationFrame(lerp);
document.body.addEventListener('pointermove', (event) => {
targetPoint.x = event.clientX;
targetPoint.y = event.clientY;
// circleEl.style.setProperty('--x', event.clientX);
// circleEl.style.setProperty('--y', event.clientY);
});
@ultrox
Copy link
Author

ultrox commented Dec 27, 2024

  • start ⋅(1−t) "how much of the start is left." ( t = 0 : all start is left)
    • (Add)
  • end⋅t "how much of the end is added."

@ultrox
Copy link
Author

ultrox commented Dec 27, 2024

const lerp = (curr, next) => {
  const delta = next - curr;
  if (Math.abs(delta) < 0.01) return next;
  return curr + (next - curr) * 0.13;
};

function createLerper() {
  let target = 0;
  let current = 0;
  let af;
  const observers = new Set();

  function animate() {
    current = lerp(current, target);

    observers.forEach((observer) => observer({ current, target }));

    if (current === target) return;

    af = requestAnimationFrame(animate);
  }

  return {
    update: (value) => {
      cancelAnimationFrame(af);
      target = +value;
      animate();
    },
    subscribe: (fn) => {
      observers.add(fn);

      fn({ current, target });
    }
  };
}

const lerper = createLerper();
// Diamond Slider
// https://codepen.io/team/keyframers/pen/ExWGGpX?editors=0010

@ultrox
Copy link
Author

ultrox commented Dec 27, 2024

const lerp = (curr, next) => {
  const delta = next - curr;
  if (Math.abs(delta) < 0.01) {
    return curr;
  }
  return curr + (next - curr) * 0.13;
};
// Reactive Timeframe Concept
// https://codepen.io/davidkpiano/pen/vxZEoO

@ultrox
Copy link
Author

ultrox commented Dec 28, 2024

function createFollowAnimation({ onUpdate }) {
  let af;
  const state = {
    targetPoint: { x: 0, y: 0 },
    currentPoint: { x: 0, y: 0 }
  };

  function lerp(start, end, t) {
    const k = (s, e) => {
      const delta = e - s;
      if (Math.abs(delta) < 0.01) {
        return e;
      }

      return s * (1 - t) + t * e;
    };

    return {
      x: k(start.x, end.x),
      y: k(start.y, end.y)
    };
  }

  function animate() {
    console.count("fko");
    cancelAnimationFrame(af);
    state.currentPoint = lerp(state.currentPoint, state.targetPoint, 0.1);

    if (state.currentPoint === state.targetPoint) {
      return;
    }

    onUpdate(state.currentPoint);
    af = requestAnimationFrame(animate);
  }

  function updateTargetPoint(x, y) {
    state.targetPoint = { x, y };
  }

  return {
    start: () => {
      document.body.parentNode.addEventListener("pointermove", (event) =>
        updateTargetPoint(event.clientX, event.clientY)
      );
      animate();
    }
  };
}

// Usage:
const animation = createFollowAnimation({
  onUpdate: (point) => {
    box.style.setProperty("--x", point.x);
    box.style.setProperty("--y", point.y);
  }
});

animation.start();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment