Skip to content

Add copy-as-function feature #2

@nico-heinrich

Description

@nico-heinrich

Hey Matthias, I love the interface of your app but I am missing a "copy as function" feature. I see that you have found a niche with the css linear functions but I would love to design my Svelte transitions using the Easing Wizard. Right now, I am using this function that takes the css linear function as argument:

export interface Point {
  x: number | null;
  y: number;
}

export function cssLinear(str: string): (t: number) => number {
  if (!str.startsWith("linear(") || !str.endsWith(")")) {
    throw new Error("Invalid linear() easing string");
  }

  // remove linear( and )
  const body = str.slice(7, -1).trim();

  // split by commas
  const parts = body.split(/\s*,\s*/);

  // parse into points { x, y }
  const points: Point[] = parts.map((part) => {
    const nums = part.trim().split(/\s+/);

    if (nums.length === 1) {
      // single value → y only, x will be filled later
      return { x: null, y: parseFloat(nums[0]) };
    }

    // value + percentage
    const y = parseFloat(nums[0]);
    const x = parseFloat(nums[1]) / 100; // convert % to [0,1]
    return { x, y };
  });

  // ensure first and last points have x
  if (points[0].x === null) points[0].x = 0;
  if (points[points.length - 1].x === null) points[points.length - 1].x = 1;

  // interpolate missing x values
  for (let i = 1; i < points.length - 1; i++) {
    if (points[i].x === null) {
      const prevX = points[i - 1].x!;
      const nextX = points.find((p, j) => j > i && p.x !== null)?.x ?? 1;

      // distribute evenly among consecutive nulls
      const nullCount = points.filter((p, j) => j >= i && p.x === null).length;
      for (let k = 0; k < nullCount; k++) {
        points[i + k].x = prevX + ((nextX - prevX) * (k + 1)) / (nullCount + 1);
      }
    }
  }

  // easing function: piecewise linear interpolation
  return (t: number): number => {
    for (let i = 0; i < points.length - 1; i++) {
      const p1 = points[i];
      const p2 = points[i + 1];
      if (t >= p1.x! && t <= p2.x!) {
        const ratio = (t - p1.x!) / (p2.x! - p1.x!);
        return p1.y + ratio * (p2.y - p1.y);
      }
    }
    return t; // fallback if out of range
  };
}

It works but feels like a crutch. Please add that tab next to CSS and Tailwind CSS :)

Cheers,

Nico

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions