Skip to content

Commit

Permalink
update content
Browse files Browse the repository at this point in the history
  • Loading branch information
g-harel committed Sep 14, 2023
1 parent d3bfbf1 commit 7f166b7
Showing 1 changed file with 114 additions and 104 deletions.
218 changes: 114 additions & 104 deletions demo/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,113 +554,19 @@ addCanvas(2, (ctx, width, height, animate) => {
drawClosed(ctx, interpolateBetween(percentage, blobA, blobB), true);
});

return `Interpolation requires points to be paired up from shape A to B. This means both blobs
must have the same number of points and that the points should be matched in a way that
minimizes movement.`;
return `The simplest way to interpolate between blobs would be to move the points that make up
the blob between the two shapes while running the smoothing pass every frame. The problem
with this approach is that it doesn't allow for any blob to map to any blob. Specifically it
would only be possible to animate between blobs that have the same number of points. This
means something more generic is required.`;
});

addCanvas(
1.3,
(ctx, width, height, animate) => {
const period = (Math.E / Math.PI) * 1000;
const center: Coord = {x: width * 0.5, y: height * 0.5};

const blob = centeredBlob(
{
extraPoints: 3,
randomness: 6,
seed: "shift",
size: height * 0.9,
},
center,
);

const shiftedBlob = shift(1, blob);

let prev = 0;
let count = 0;
animate((frameTime) => {
const animationTime = mod(frameTime, period);
const percentage = timingFunctions.ease(mod(animationTime, period) / period);

// Count animation loops.
if (percentage < prev) count++;
prev = percentage;

// Draw lines points are travelling.
tempStyles(
ctx,
() => {
ctx.fillStyle = colors.secondary;
ctx.strokeStyle = colors.secondary;
},
() => {
drawPoint(ctx, center, 2);
forPoints(blob, ({curr, next}) => {
drawLine(ctx, curr, next(), 1, 2);
});
},
);

// Pause in-place every other animation loop.
if (count % 2 === 0) {
drawClosed(ctx, interpolateBetweenSmooth(2, percentage, blob, shiftedBlob), true);
} else {
drawClosed(ctx, blob, true);
}
});

return `Points cannot be swapped without resulting in a different shape. However, a likely
enough optimal order can be selected by shifting the points and comparing the point
position deltas.`;
},
(ctx, width, height, animate) => {
const period = Math.PI * Math.E * 1000;
const center: Coord = {x: width * 0.5, y: height * 0.5};

const blob = centeredBlob(
{
extraPoints: 3,
randomness: 6,
seed: "flip",
size: height * 0.9,
},
center,
);
const reversedBlob = mapPoints(blob, ({curr}) => {
const temp = curr.handleIn;
curr.handleIn = curr.handleOut;
curr.handleOut = temp;
return curr;
});
reversedBlob.reverse();

animate((frameTime) => {
const percentage = calcBouncePercentage(period, timingFunctions.ease, frameTime);

forceStyles(ctx, () => {
const {pt} = sizes();
ctx.fillStyle = "transparent";
ctx.lineWidth = pt;
ctx.strokeStyle = colors.secondary;
ctx.setLineDash([2 * pt]);
drawClosed(ctx, blob, false);
});

drawClosed(ctx, interpolateBetweenSmooth(2, percentage, blob, reversedBlob), true);
});

return `The only safe re-ordering is to reverse the points and again iterate through all
possible shifts.`;
},
);

addCanvas(
1.3,
(ctx, width, height, animate) => {
const period = Math.PI * 1000;
const center: Coord = {x: width * 0.5, y: height * 0.5};
const maxExtraPoints = 4;
const maxExtraPoints = 7;
const period = maxExtraPoints * Math.PI * 400;
const {pt} = sizes();

const blob = centeredBlob(
Expand Down Expand Up @@ -695,8 +601,12 @@ addCanvas(
});
});

return `Points are added until they both have the same count. These new points should be as
evenly distributed as possible.`;
return `The first step to prepare animation is to make the number of points between the
start and end shapes equal. This is done by adding points to the shape with least points
until they are both equal.
<br><br>
For best animation quality it is important that these points are as evenly distributed
as possible all around the shape so this is not a recursive algorithm.`;
},
(ctx, width, height, animate) => {
const period = Math.PI ** Math.E * 1000;
Expand Down Expand Up @@ -759,11 +669,111 @@ addCanvas(
);
});

return `Curve splitting uses the innermost line from the cubic bezier curve drawing demo and
return `It is only possible to reliably <i>add</i> points to a blob because attempting to
remove points without modifying the shape is almost never possible and is expensive to
compute.
Curve splitting uses the innermost line from the cubic bezier curve drawing demo and
makes either side of the final point the handles.`;
},
);

addCanvas(
1.3,
(ctx, width, height, animate) => {
const period = (Math.E / Math.PI) * 1000;
const center: Coord = {x: width * 0.5, y: height * 0.5};

const blob = centeredBlob(
{
extraPoints: 3,
randomness: 6,
seed: "shift",
size: height * 0.9,
},
center,
);

const shiftedBlob = shift(1, blob);

let prev = 0;
let count = 0;
animate((frameTime) => {
const animationTime = mod(frameTime, period);
const percentage = timingFunctions.ease(mod(animationTime, period) / period);

// Count animation loops.
if (percentage < prev) count++;
prev = percentage;

// Draw lines points are travelling.
tempStyles(
ctx,
() => {
ctx.fillStyle = colors.secondary;
ctx.strokeStyle = colors.secondary;
},
() => {
drawPoint(ctx, center, 2);
forPoints(blob, ({curr, next}) => {
drawLine(ctx, curr, next(), 1, 2);
});
},
);

// Pause in-place every other animation loop.
if (count % 2 === 0) {
drawClosed(ctx, interpolateBetweenSmooth(2, percentage, blob, shiftedBlob), true);
} else {
drawClosed(ctx, blob, true);
}
});

return `Points cannot be swapped without resulting in a different shape. However, a likely
enough optimal order can be selected by shifting the points and comparing the point
position deltas.`;
},
(ctx, width, height, animate) => {
const period = Math.PI * Math.E * 1000;
const center: Coord = {x: width * 0.5, y: height * 0.5};

const blob = centeredBlob(
{
extraPoints: 3,
randomness: 6,
seed: "flip",
size: height * 0.9,
},
center,
);
const reversedBlob = mapPoints(blob, ({curr}) => {
const temp = curr.handleIn;
curr.handleIn = curr.handleOut;
curr.handleOut = temp;
return curr;
});
reversedBlob.reverse();

animate((frameTime) => {
const percentage = calcBouncePercentage(period, timingFunctions.ease, frameTime);

forceStyles(ctx, () => {
const {pt} = sizes();
ctx.fillStyle = "transparent";
ctx.lineWidth = pt;
ctx.strokeStyle = colors.secondary;
ctx.setLineDash([2 * pt]);
drawClosed(ctx, blob, false);
});

drawClosed(ctx, interpolateBetweenSmooth(2, percentage, blob, reversedBlob), true);
});

return `The only safe re-ordering is to reverse the points and again iterate through all
possible shifts.`;
},
);

addCanvas(1.8, (ctx, width, height) => {
// Only animate in the most recent painter call.
const animationID = Math.random();
Expand Down

0 comments on commit 7f166b7

Please sign in to comment.