Skip to content

Commit 7a25f29

Browse files
committed
publish #7 as beta release
1 parent bdb8c9b commit 7a25f29

File tree

7 files changed

+135
-132
lines changed

7 files changed

+135
-132
lines changed

demo/content.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,10 @@ addCanvas(
271271
);
272272

273273
// Draw randomly shifted shape.
274-
const shiftedShape = shape.map(
275-
(p): Point => {
276-
const randOffset = percentage * (randStrength * rgen() - randStrength / 2);
277-
return coordPoint(splitLine(randOffset, p, center));
278-
},
279-
);
274+
const shiftedShape = shape.map((p): Point => {
275+
const randOffset = percentage * (randStrength * rgen() - randStrength / 2);
276+
return coordPoint(splitLine(randOffset, p, center));
277+
});
280278

281279
drawClosed(ctx, shiftedShape, true);
282280
});

demo/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,17 @@
132132
<nav>
133133
<a
134134
href="https://github.com/g-harel/blobs"
135-
style="transform: rotate(1deg) translateY(3px);"
135+
style="transform: rotate(1deg) translateY(3px)"
136136
>GITHUB</a
137137
>
138138
<a
139139
href="https://npmjs.com/package/blobs"
140-
style="transform: rotate(-2deg) translateY(-1px);"
140+
style="transform: rotate(-2deg) translateY(-1px)"
141141
>NPM</a
142142
>
143143
<a
144144
href="mailto:gabrielj.harel@gmail.com"
145-
style="transform: rotate(4deg) translateY(1px);"
145+
style="transform: rotate(4deg) translateY(1px)"
146146
>CONTACT</a
147147
>
148148
</nav>

internal/animate/state.ts

Lines changed: 84 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -9,86 +9,88 @@ interface CallbackStore {
99
[frameId: string]: () => void;
1010
}
1111

12-
export const statefulAnimationGenerator = <K extends CallbackKeyframe, T>(
13-
generator: (keyframe: K) => Point[],
14-
renderer: (points: Point[]) => T,
15-
checker: (keyframe: K, index: number) => void,
16-
) => () => {
17-
let internalFrames: InternalKeyframe[] = [];
18-
let renderCache: RenderCache = {};
19-
let callbackStore: CallbackStore = {};
20-
21-
// Keep track of paused state.
22-
let pausedAt = 0;
23-
let pauseOffset = 0;
24-
const getAnimationTimestamp = () => Date.now() - pauseOffset;
25-
const isPaused = () => pausedAt !== 0;
26-
27-
const play = () => {
28-
if (!isPaused()) return;
29-
pauseOffset += getAnimationTimestamp() - pausedAt;
30-
pausedAt = 0;
12+
export const statefulAnimationGenerator =
13+
<K extends CallbackKeyframe, T>(
14+
generator: (keyframe: K) => Point[],
15+
renderer: (points: Point[]) => T,
16+
checker: (keyframe: K, index: number) => void,
17+
) =>
18+
() => {
19+
let internalFrames: InternalKeyframe[] = [];
20+
let renderCache: RenderCache = {};
21+
let callbackStore: CallbackStore = {};
22+
23+
// Keep track of paused state.
24+
let pausedAt = 0;
25+
let pauseOffset = 0;
26+
const getAnimationTimestamp = () => Date.now() - pauseOffset;
27+
const isPaused = () => pausedAt !== 0;
28+
29+
const play = () => {
30+
if (!isPaused()) return;
31+
pauseOffset += getAnimationTimestamp() - pausedAt;
32+
pausedAt = 0;
33+
};
34+
35+
const pause = () => {
36+
if (isPaused()) return;
37+
pausedAt = getAnimationTimestamp();
38+
};
39+
40+
const playPause = () => {
41+
``;
42+
if (isPaused()) {
43+
play();
44+
} else {
45+
pause();
46+
}
47+
};
48+
49+
const renderFrame = (): T => {
50+
const renderOutput = renderFramesAt({
51+
renderCache: renderCache,
52+
timestamp: isPaused() ? pausedAt : getAnimationTimestamp(),
53+
currentFrames: internalFrames,
54+
});
55+
56+
// Update render cache with returned value.
57+
renderCache = renderOutput.renderCache;
58+
59+
// Invoke callback if defined and the first time the frame is reached.
60+
if (renderOutput.lastFrameId && callbackStore[renderOutput.lastFrameId]) {
61+
callbackStore[renderOutput.lastFrameId]();
62+
delete callbackStore[renderOutput.lastFrameId];
63+
}
64+
65+
return renderer(renderOutput.points);
66+
};
67+
68+
const transition = (...keyframes: K[]) => {
69+
// Make sure frame info is valid.
70+
for (let i = 0; i < keyframes.length; i++) {
71+
checker(keyframes[i], i);
72+
}
73+
74+
const transitionOutput = transitionFrames<K>({
75+
renderCache: renderCache,
76+
timestamp: getAnimationTimestamp(),
77+
currentFrames: internalFrames,
78+
newFrames: keyframes,
79+
shapeGenerator: generator,
80+
});
81+
82+
// Reset internal state..
83+
internalFrames = transitionOutput.newFrames;
84+
callbackStore = {};
85+
renderCache = {};
86+
87+
// Populate callback store using returned frame ids.
88+
for (const newFrame of internalFrames) {
89+
if (newFrame.isSynthetic) continue;
90+
const {callback} = keyframes[newFrame.transitionSourceFrameIndex];
91+
if (callback) callbackStore[newFrame.id] = callback;
92+
}
93+
};
94+
95+
return {renderFrame, transition, play, pause, playPause};
3196
};
32-
33-
const pause = () => {
34-
if (isPaused()) return;
35-
pausedAt = getAnimationTimestamp();
36-
};
37-
38-
const playPause = () => {
39-
``;
40-
if (isPaused()) {
41-
play();
42-
} else {
43-
pause();
44-
}
45-
};
46-
47-
const renderFrame = (): T => {
48-
const renderOutput = renderFramesAt({
49-
renderCache: renderCache,
50-
timestamp: isPaused() ? pausedAt : getAnimationTimestamp(),
51-
currentFrames: internalFrames,
52-
});
53-
54-
// Update render cache with returned value.
55-
renderCache = renderOutput.renderCache;
56-
57-
// Invoke callback if defined and the first time the frame is reached.
58-
if (renderOutput.lastFrameId && callbackStore[renderOutput.lastFrameId]) {
59-
callbackStore[renderOutput.lastFrameId]();
60-
delete callbackStore[renderOutput.lastFrameId];
61-
}
62-
63-
return renderer(renderOutput.points);
64-
};
65-
66-
const transition = (...keyframes: K[]) => {
67-
// Make sure frame info is valid.
68-
for (let i = 0; i < keyframes.length; i++) {
69-
checker(keyframes[i], i);
70-
}
71-
72-
const transitionOutput = transitionFrames<K>({
73-
renderCache: renderCache,
74-
timestamp: getAnimationTimestamp(),
75-
currentFrames: internalFrames,
76-
newFrames: keyframes,
77-
shapeGenerator: generator,
78-
});
79-
80-
// Reset internal state..
81-
internalFrames = transitionOutput.newFrames;
82-
callbackStore = {};
83-
renderCache = {};
84-
85-
// Populate callback store using returned frame ids.
86-
for (const newFrame of internalFrames) {
87-
if (newFrame.isSynthetic) continue;
88-
const {callback} = keyframes[newFrame.transitionSourceFrameIndex];
89-
if (callback) callbackStore[newFrame.id] = callback;
90-
}
91-
};
92-
93-
return {renderFrame, transition, play, pause, playPause};
94-
};

internal/animate/timing.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ const ease: TimingFunc = (p) => {
1818
return 0.5 + 0.5 * Math.sin(Math.PI * (p + 1.5));
1919
};
2020

21-
const elasticEnd = (s: number): TimingFunc => (p) => {
22-
return Math.pow(2, -10 * p) * Math.sin(((p - s / 4) * (2 * Math.PI)) / s) + 1;
23-
};
21+
const elasticEnd =
22+
(s: number): TimingFunc =>
23+
(p) => {
24+
return Math.pow(2, -10 * p) * Math.sin(((p - s / 4) * (2 * Math.PI)) / s) + 1;
25+
};
2426

2527
// https://www.desmos.com/calculator/fqisoq1kuw
2628
export const timingFunctions = {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "blobs",
3-
"version": "2.2.0",
3+
"version": "2.2.1-beta.0",
44
"description": "Random blob generation and animation",
55
"author": "g-harel",
66
"license": "MIT",
@@ -66,7 +66,7 @@
6666
},
6767
"husky": {
6868
"hooks": {
69-
"pre-commit": "yarn run fmt && yarn run test && yarn run demo:build && git add -A ."
69+
"pre-commit": "yarn run fmt && yarn run test && git add -A ."
7070
}
7171
}
7272
}

public/blobs.test.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,24 @@ interface TestCase<T> {
2424
error?: RegExp;
2525
}
2626

27-
const runSuite = <T>(t: {
28-
optionsGenerator: () => T;
29-
functionBeingTested: (options: any) => void;
30-
}) => (testCases: TestCase<T>[]) => {
31-
for (const testCase of testCases) {
32-
it(testCase.name, () => {
33-
const options = t.optionsGenerator();
34-
testCase.edit(options);
27+
const runSuite =
28+
<T>(t: {optionsGenerator: () => T; functionBeingTested: (options: any) => void}) =>
29+
(testCases: TestCase<T>[]) => {
30+
for (const testCase of testCases) {
31+
it(testCase.name, () => {
32+
const options = t.optionsGenerator();
33+
testCase.edit(options);
3534

36-
if (testCase.error) {
37-
// Copy regexp because they are stateful.
38-
const pattern = new RegExp(testCase.error);
39-
expect(() => t.functionBeingTested(options)).toThrow(pattern);
40-
} else {
41-
expect(() => t.functionBeingTested(options)).not.toThrow();
42-
}
43-
});
44-
}
45-
};
35+
if (testCase.error) {
36+
// Copy regexp because they are stateful.
37+
const pattern = new RegExp(testCase.error);
38+
expect(() => t.functionBeingTested(options)).toThrow(pattern);
39+
} else {
40+
expect(() => t.functionBeingTested(options)).not.toThrow();
41+
}
42+
});
43+
}
44+
};
4645

4746
const testBlobOptions = (functionBeingTested: (options: any) => void) => {
4847
it("should accept generated blobOptions", () => {

rollup.config.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,23 @@ const bundles = [
2929
},
3030
];
3131

32-
export default bundles.map((bundle) => ({
33-
input: bundle.entry,
34-
output: {
35-
file: bundle.output + "/index.js",
36-
format: "umd",
37-
name: bundle.name,
38-
sourcemap: true,
39-
},
40-
plugins: [
41-
typescript({cacheRoot: "./node_modules/.cache/rpt2"}),
42-
uglify(),
43-
copy({
44-
hook: "writeBundle",
45-
targets: [{src: bundle.types, dest: bundle.output, rename: "index.d.ts"}],
46-
verbose: true,
47-
}),
48-
],
49-
}));
32+
export default ["es", "umd"].flatMap((format) =>
33+
bundles.map((bundle) => ({
34+
input: bundle.entry,
35+
output: {
36+
file: bundle.output + `/index${format == "es" ? ".module" : ""}.js`,
37+
format: format,
38+
name: bundle.name,
39+
sourcemap: true,
40+
},
41+
plugins: [
42+
typescript({cacheRoot: "./node_modules/.cache/rpt2"}),
43+
uglify(),
44+
copy({
45+
hook: "writeBundle",
46+
targets: [{src: bundle.types, dest: bundle.output, rename: "index.d.ts"}],
47+
verbose: true,
48+
}),
49+
],
50+
})),
51+
);

0 commit comments

Comments
 (0)