Initial blob shape

This commit is contained in:
Jake Archibald
2020-11-25 15:13:53 +00:00
parent 4d5761c780
commit fcef2b2d3e
4 changed files with 123 additions and 51 deletions

View File

@@ -1,9 +1,10 @@
import * as style from './style.css';
import * as style from '../style.css';
import { startBlobs, blobColor } from './meta';
/**
* Control point x,y - point x,y - control point x,y
*/
type BlobPoint = [number, number, number, number, number, number];
export type BlobPoint = [number, number, number, number, number, number];
const maxRandomDistance = 0.25;
@@ -47,46 +48,6 @@ const sevenPointCircle: BlobPoint[] = [
[-0.972, -0.386, -0.782, -0.623, -0.592, -0.861],
];
/** Start points, for the shape we use in prerender */
const startPoints: BlobPoint[][] = [
[
[-0.232, -1.029, 0.073, -1.029, 0.377, -1.029],
[0.565, -1.098, 0.755, -0.86, 0.945, -0.622],
[0.917, -0.01, 0.849, 0.286, 0.782, 0.583],
[0.85, 0.687, 0.576, 0.819, 0.302, 0.951],
[-0.198, 1.009, -0.472, 0.877, -0.746, 0.745],
[-0.98, 0.513, -1.048, 0.216, -1.116, -0.08],
[-0.964, -0.395, -0.774, -0.633, -0.584, -0.871],
],
[
[-0.505, -1.109, -0.201, -1.109, 0.104, -1.109],
[0.641, -0.684, 0.831, -0.446, 1.02, -0.208],
[1.041, 0.034, 0.973, 0.331, 0.905, 0.628],
[0.734, 0.794, 0.46, 0.926, 0.186, 1.058],
[-0.135, 0.809, -0.409, 0.677, -0.684, 0.545],
[-0.935, 0.404, -1.002, 0.108, -1.07, -0.189],
[-0.883, -0.402, -0.693, -0.64, -0.503, -0.878],
],
[
[-0.376, -1.168, -0.071, -1.168, 0.233, -1.168],
[0.732, -0.956, 0.922, -0.718, 1.112, -0.48],
[1.173, 0.027, 1.105, 0.324, 1.038, 0.621],
[0.707, 0.81, 0.433, 0.943, 0.159, 1.075],
[-0.096, 1.135, -0.37, 1.003, -0.644, 0.871],
[-0.86, 0.457, -0.927, 0.161, -0.995, -0.136],
[-0.87, -0.516, -0.68, -0.754, -0.49, -0.992],
],
[
[-0.309, -0.998, -0.004, -0.998, 0.3, -0.998],
[0.535, -0.852, 0.725, -0.614, 0.915, -0.376],
[1.05, -0.09, 0.982, 0.207, 0.915, 0.504],
[0.659, 0.807, 0.385, 0.939, 0.111, 1.071],
[-0.178, 1.048, -0.452, 0.916, -0.727, 0.784],
[-0.942, 0.582, -1.009, 0.285, -1.077, -0.011],
[-1.141, -0.335, -0.951, -0.573, -0.761, -0.811],
],
];
/*
// Should it be needed, here's how the above was created:
function createBezierCirclePoints(points: number): BlobPoint[] {
@@ -154,9 +115,27 @@ class CentralBlobs {
private rotatePos: number = 0;
private blobs = Array.from(
{ length: 4 },
(_, i) => new CircleBlob(sevenPointCircle, startPoints[i]),
(_, i) => new CircleBlob(sevenPointCircle, startBlobs[i]),
);
constructor() {
console.log(
`WARNING: There's a debug key listener here that must be removed before going live`,
);
addEventListener('keyup', (event) => {
if (event.key !== 'b') return;
console.log(
JSON.stringify(
this.blobs.map((blob) =>
blob
.frame(0)
.map((points) => points.map((point) => Number(point.toFixed(3)))),
),
),
);
});
}
draw(
ctx: CanvasRenderingContext2D,
timeDelta: number,
@@ -235,7 +214,6 @@ export function startBlobAnim(canvas: HTMLCanvasElement) {
deltaMultiplier = Math.max(0, deltaMultiplier - deltaMultiplierStep);
if (deltaMultiplier === 0) {
animating = false;
console.log(centralBlobs);
return;
}
} else if (deltaMultiplier !== 1) {
@@ -250,7 +228,7 @@ export function startBlobAnim(canvas: HTMLCanvasElement) {
canvas.height = canvasBounds.height * devicePixelRatio;
const loadImgBounds = loadImgEl.getBoundingClientRect();
ctx.fillStyle = 'rgba(255, 0, 102, 0.3)';
ctx.fillStyle = blobColor;
ctx.scale(devicePixelRatio, devicePixelRatio);
centralBlobs.draw(
@@ -258,7 +236,7 @@ export function startBlobAnim(canvas: HTMLCanvasElement) {
delta,
loadImgBounds.left - canvasBounds.left + loadImgBounds.width / 2,
loadImgBounds.top - canvasBounds.top + loadImgBounds.height / 2,
(loadImgBounds.width / 2) * (1 - maxRandomDistance),
loadImgBounds.height / 2 / (1 + maxRandomDistance),
);
requestAnimationFrame(frame);

View File

@@ -0,0 +1,43 @@
import type { BlobPoint } from '.';
/** Start points, for the shape we use in prerender */
export const startBlobs: BlobPoint[][] = [
[
[-0.232, -1.029, 0.073, -1.029, 0.377, -1.029],
[0.565, -1.098, 0.755, -0.86, 0.945, -0.622],
[0.917, -0.01, 0.849, 0.286, 0.782, 0.583],
[0.85, 0.687, 0.576, 0.819, 0.302, 0.951],
[-0.198, 1.009, -0.472, 0.877, -0.746, 0.745],
[-0.98, 0.513, -1.048, 0.216, -1.116, -0.08],
[-0.964, -0.395, -0.774, -0.633, -0.584, -0.871],
],
[
[-0.505, -1.109, -0.201, -1.109, 0.104, -1.109],
[0.641, -0.684, 0.831, -0.446, 1.02, -0.208],
[1.041, 0.034, 0.973, 0.331, 0.905, 0.628],
[0.734, 0.794, 0.46, 0.926, 0.186, 1.058],
[-0.135, 0.809, -0.409, 0.677, -0.684, 0.545],
[-0.935, 0.404, -1.002, 0.108, -1.07, -0.189],
[-0.883, -0.402, -0.693, -0.64, -0.503, -0.878],
],
[
[-0.376, -1.168, -0.071, -1.168, 0.233, -1.168],
[0.732, -0.956, 0.922, -0.718, 1.112, -0.48],
[1.173, 0.027, 1.105, 0.324, 1.038, 0.621],
[0.707, 0.81, 0.433, 0.943, 0.159, 1.075],
[-0.096, 1.135, -0.37, 1.003, -0.644, 0.871],
[-0.86, 0.457, -0.927, 0.161, -0.995, -0.136],
[-0.87, -0.516, -0.68, -0.754, -0.49, -0.992],
],
[
[-0.309, -0.998, -0.004, -0.998, 0.3, -0.998],
[0.535, -0.852, 0.725, -0.614, 0.915, -0.376],
[1.05, -0.09, 0.982, 0.207, 0.915, 0.504],
[0.659, 0.807, 0.385, 0.939, 0.111, 1.071],
[-0.178, 1.048, -0.452, 0.916, -0.727, 0.784],
[-0.942, 0.582, -1.009, 0.285, -1.077, -0.011],
[-1.141, -0.335, -0.951, -0.573, -0.761, -0.811],
],
];
export const blobColor = 'rgba(255, 0, 102, 0.3)';

View File

@@ -14,6 +14,7 @@ import logoWithText from 'url:./imgs/logo-with-text.svg';
import * as style from './style.css';
import type SnackBarElement from 'shared/initial-app/custom-els/snack-bar';
import 'shared/initial-app/custom-els/snack-bar';
import { blobColor, startBlobs } from './blob-anim/meta';
const demos = [
{
@@ -42,7 +43,10 @@ const demos = [
},
];
const blobAnimImport = import('./blob-anim');
const blobAnimImport =
!__PRERENDER__ && matchMedia('(prefers-reduced-motion: reduce)').matches
? undefined
: import('./blob-anim');
const installButtonSource = 'introInstallButton-Purple';
const supportsClipboardAPI =
!__PRERENDER__ && navigator.clipboard && navigator.clipboard.read;
@@ -63,10 +67,13 @@ interface Props {
interface State {
fetchingDemoIndex?: number;
beforeInstallEvent?: BeforeInstallPromptEvent;
showBlobSVG: boolean;
}
export default class Intro extends Component<Props, State> {
state: State = {};
state: State = {
showBlobSVG: true,
};
private fileInput?: HTMLInputElement;
private blobCanvas?: HTMLCanvasElement;
private installingViaButton = false;
@@ -81,7 +88,16 @@ export default class Intro extends Component<Props, State> {
// Listen for the appinstalled event, indicating Squoosh has been installed.
window.addEventListener('appinstalled', this.onAppInstalled);
blobAnimImport.then((module) => module.startBlobAnim(this.blobCanvas!));
if (blobAnimImport) {
blobAnimImport.then((module) => {
this.setState(
{
showBlobSVG: false,
},
() => module.startBlobAnim(this.blobCanvas!),
);
});
}
}
componentWillUnmount() {
@@ -198,7 +214,10 @@ export default class Intro extends Component<Props, State> {
this.props.onFile!(new File([blob], 'image.unknown'));
};
render({}: Props, { fetchingDemoIndex, beforeInstallEvent }: State) {
render(
{}: Props,
{ fetchingDemoIndex, beforeInstallEvent, showBlobSVG }: State,
) {
return (
<div class={style.intro}>
<input
@@ -227,6 +246,31 @@ export default class Intro extends Component<Props, State> {
/>
</h1>
<div class={style.loadImg}>
{showBlobSVG && (
<svg
class={style.blobSvg}
style={{ fill: blobColor }}
viewBox="-1.25 -1.25 2.5 2.5"
>
{startBlobs.map((points) => (
<path
d={points
.map((point, i) => {
const nextI = i === points.length - 1 ? 0 : i + 1;
let d = '';
if (i === 0) {
d += `M${point[2]} ${point[3]}`;
}
return (
d +
`C${point[4]} ${point[5]} ${points[nextI][0]} ${points[nextI][1]} ${points[nextI][2]} ${points[nextI][3]}`
);
})
.join('')}
/>
))}
</svg>
)}
<div
class={style.loadImgContent}
style={{ visibility: __PRERENDER__ ? 'hidden' : '' }}

View File

@@ -24,7 +24,7 @@
}
.logo-container {
margin: 8rem 0 -1.2rem;
margin: 8rem 0 1rem;
}
.logo {
@@ -40,7 +40,14 @@
font-size: 1.2rem;
}
.blob-svg {
composes: abs-fill from '../util.css';
width: 100%;
height: 100%;
}
.load-img-content {
position: relative;
--size: 36rem;
width: var(--size);
height: var(--size);