Skip to content

Commit

Permalink
make wiggle transition also wiggle
Browse files Browse the repository at this point in the history
  • Loading branch information
g-harel committed Sep 24, 2023
1 parent 378ae27 commit 5c7f3c0
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 44 deletions.
9 changes: 5 additions & 4 deletions demo/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -878,10 +878,11 @@ addCanvas(
animation.transition({
points: pointy,
duration: 1000,
callback: () => animation.transition({
points: wobblyGerm,
duration: 4000,
}),
callback: () =>
animation.transition({
points: wobblyGerm,
duration: 4000,
}),
});

animate(() => drawClosed(ctx, animation.renderPoints(), true));
Expand Down
27 changes: 9 additions & 18 deletions demo/example.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {CanvasKeyframe, canvasPath, wigglePreset} from "../public/animate";
import {drawDebugClosed, drawPoint} from "./internal/canvas";
import {drawHandles, drawPoint} from "./internal/canvas";
import {isDebug} from "./internal/debug";
import {colors} from "./internal/layout";

// Fetch reference to example container.
Expand Down Expand Up @@ -32,22 +33,12 @@ const renderFrame = () => {
ctx.fillStyle = colors.highlight;
ctx.strokeStyle = colors.highlight;

// Debug
if (false) {
const p = (animation as any).renderPoints();

drawDebugClosed(ctx, p, 60);
if (p.length) drawPoint(ctx, p[0], 400);

const handleLength = p[0]?.handleIn.length;
if (handleLength < 100) {
console.log("shorty detected: ", handleLength);
return;
if (isDebug()) {
const points = animation.renderPoints();
for (const point of points) {
drawPoint(ctx, point, 2);
drawHandles(ctx, point, 1);
}

const fps = 20;
setTimeout(() => requestAnimationFrame(renderFrame), 1000 / fps);
return;
}

ctx.fill(animation.renderFrame());
Expand All @@ -68,7 +59,7 @@ const genWiggle = (transition: number) => {
size,
},
{},
{speed: 2, initialTransition: transition, initialTimingFunction: "ease"},
{speed: 2, initialTransition: transition},
);
};

Expand All @@ -93,7 +84,7 @@ const genFrame = (overrides: any = {}): CanvasKeyframe => {
// Callback for every frame which starts transition to a new frame.
const loopAnimation = (): void => {
extraPoints = 0;
genWiggle(4000);
genWiggle(2000);
};

// Quickly animate to a new frame when canvas is clicked.
Expand Down
2 changes: 1 addition & 1 deletion demo/internal/debug.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// If debug is initially set to false it will not be toggleable.
let debug = true && location.hostname === "localhost";
let debug = window.location.search.includes("debug") && location.hostname === "localhost";
export const isDebug = () => debug;

const debugListeners: ((debug: boolean) => void)[] = [];
Expand Down
2 changes: 1 addition & 1 deletion internal/animate/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const statefulAnimationGenerator = <K extends CallbackKeyframe, T>(

// Invoke callback if defined and the first time the frame is reached.
if (renderOutput.lastFrameId && frameCallbackStore[renderOutput.lastFrameId]) {
frameCallbackStore[renderOutput.lastFrameId]();
setTimeout(frameCallbackStore[renderOutput.lastFrameId]);
delete frameCallbackStore[renderOutput.lastFrameId];
}

Expand Down
70 changes: 50 additions & 20 deletions public/animate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
} from "../internal/check";
import {BlobOptions, CanvasOptions} from "./blobs";
import {noise} from "../internal/rand";
import {interpolateBetween} from "../internal/animate/interpolate";
import {prepare} from "../internal/animate/prepare";

interface Keyframe {
// Duration of the keyframe animation in milliseconds.
Expand Down Expand Up @@ -82,15 +84,9 @@ export interface TimestampProvider {
export interface WiggleOptions {
// Speed of the wiggle movement. Higher is faster.
speed: number;
// Delay before the first wiggle frame.
// Default: 0
initialDelay?: number;
// Length of the transition from the current state to the wiggle blob.
// Default: 0
initialTransition?: number;
// Interpolation function.
// Default: linear
initialTimingFunction?: Keyframe["timingFunction"];
}

const canvasPointGenerator = (keyframe: CanvasKeyframe | CanvasCustomKeyframe): Point[] => {
Expand Down Expand Up @@ -147,27 +143,61 @@ export const wigglePreset = (
canvasOptions: CanvasOptions,
wiggleOptions: WiggleOptions,
) => {
const leapSize = 0.01 * wiggleOptions.speed;

// Interval at which a new sample is taken.
// Multiple of 16 to do work every N frames.
const intervalMs = 16 * 5;

const leapSize = 0.01 * wiggleOptions.speed;
const noiseField = noise(String(blobOptions.seed));

const transitionFrameCount = 1 + Math.min((wiggleOptions.initialTransition || 0) / intervalMs);
let transitionStartFrame = animation.renderPoints();

let count = 0;
const loopAnimation = (first?: boolean, delay?: number) => {
const loopAnimation = () => {
count++;
animation.transition({
duration: first ? wiggleOptions.initialTransition || 0 : intervalMs,
delay: delay || 0,
timingFunction: (first && wiggleOptions.initialTimingFunction) || "linear",
canvasOptions,
points: genFromOptions(blobOptions, (index) => {
return noiseField(leapSize * count, index);
}),
callback: loopAnimation,

// Constantly changing blob.
const noiseBlob = genFromOptions(blobOptions, (index) => {
return noiseField(leapSize * count, index);
});

if (count < transitionFrameCount) {
// Create intermediate frame between the current state and the
// moving noiseBlob target.
const [preparedStartPoints, preparedEndPoints] = prepare(
transitionStartFrame,
noiseBlob,
{
rawAngles: true,
divideRatio: 1,
},
);
const progress = 1 / (transitionFrameCount - count);
const targetPoints = interpolateBetween(
progress,
preparedStartPoints,
preparedEndPoints,
);
transitionStartFrame = targetPoints;

animation.transition({
duration: intervalMs,
delay: 0,
timingFunction: "linear",
canvasOptions,
points: targetPoints,
callback: loopAnimation,
});
} else {
animation.transition({
duration: intervalMs,
delay: 0,
timingFunction: "linear",
canvasOptions,
points: noiseBlob,
callback: loopAnimation,
});
}
};
loopAnimation(true, wiggleOptions.initialDelay);
loopAnimation();
};

0 comments on commit 5c7f3c0

Please sign in to comment.