augustkline.com/src/main.ts

219 lines
7.4 KiB
TypeScript

import sunsetfourteenth from "/14thstsunrise.gif";
import backwalkgeorge from "/backwalkgeorge.jpg";
import ducklings from "/ducklings.gif";
import ermine from "/ermine.gif";
import fieldnotes from "/fieldnotes.gif";
import flowers from "/flowers.jpg";
import georgerasp from "/georgerasp.gif";
import georgetoilet from "/georgetoilet.jpg";
import heron from "/heron.jpg";
import klinefloor from "/klinefloor.jpg";
import klinemirror from "/klinemirror.jpg";
import klineoutside from "/klineoutside.jpg";
import klinetrain from "/klinetrain.jpg";
import lamp from "/lamp.gif";
import mirror from "/mirror.jpg";
import ohio from "/ohio.jpg";
import sashaklineburrito from "/sashaklineburrito.jpg";
import sashaklinecar from "/sashaklinecar.jpg";
import solderkitty from "/solderkitty.jpg";
import sunsetkline from "/sunsetkline.jpg";
const background = document.getElementById("background")!;
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)",
).matches;
const setImages = () => {
let images: string[] = [];
let alts: string[] = [];
if (prefersReducedMotion) {
images = [
backwalkgeorge,
fieldnotes,
flowers,
georgetoilet,
heron,
klinefloor,
klinemirror,
klineoutside,
klinetrain,
mirror,
ohio,
sashaklineburrito,
sashaklinecar,
solderkitty,
sunsetkline,
];
alts = [
"A small child holding a stuffed monkey and a santa hat walking away from the camera",
"Animated gif of a notebook with a pretty landscape illustration cover",
"A field of violet flowers",
"A woman smiling next to a stuffed monkey",
"A heron standing in a pond",
"A woman in a green sweater and jeans sitting on the floor and smiling",
"A woman in bed taking a mirror selfie where her face is distorted",
"A selfie of a woman in a driveway next to a truck",
"A young girl smiling in front of a train",
"A shattered mirror",
"Two adjacent houses lit by an early morning sunrise",
"A selfie of two friends holding burritos, one of whom is wearing a cammo hat",
"A selfie of two friends in a car, one of whom is wearing a cammo hat",
"A pink porcelain kitty figurine supporting a soldering iron",
"A selfie of a woman indoors, behind her the sun is setting in the window",
];
} else {
images = [
sunsetfourteenth,
backwalkgeorge,
ducklings,
ermine,
fieldnotes,
flowers,
georgerasp,
georgetoilet,
heron,
klinefloor,
klinemirror,
klineoutside,
klinetrain,
lamp,
mirror,
ohio,
sashaklineburrito,
sashaklinecar,
solderkitty,
sunsetkline,
];
alts = [
"Animated gif of a sunrise on a city street",
"A small child holding a stuffed monkey and a santa hat walking away from the camera",
"Animated gif of a duck and ducklings swimming in a pond",
"Animated gif of an ermine peeking up out of a crack in concrete",
"Animated gif of a notebook with a pretty landscape illustration cover",
"A field of violet flowers",
"Animated gif of an amber CRT screen with flashing text and Raspberry Pi logo",
"A woman smiling next to a stuffed monkey",
"A heron standing in a pond",
"A woman in a green sweater and jeans sitting on the floor and smiling",
"A woman in bed taking a mirror selfie where her face is distorted",
"A selfie of a woman in a driveway next to a truck",
"A young girl smiling in front of a train",
"Animated gif of a lamp behind which cars drive past in the snow",
"A shattered mirror",
"Two adjacent houses lit by an early morning sunrise",
"A selfie of two friends holding burritos, one of whom is wearing a cammo hat",
"A selfie of two friends in a car, one of whom is wearing a cammo hat",
"A pink porcelain kitty figurine supporting a soldering iron",
"A selfie of a woman indoors, behind her the sun is setting in the window",
];
}
const randn_bm = (mean = 0, stdev = 0.4) => {
const u = 1 - Math.random();
const v = Math.random();
const z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
return z * stdev + mean;
};
const randNums = (count: number, minDistance: number): number[] => {
const numbers: number[] = [];
function isFarEnough(num: number): boolean {
for (const n of numbers) {
if (Math.abs(num - n) < minDistance) {
return false;
}
}
return true;
}
while (numbers.length < count) {
const newNumber = randn_bm();
if (isFarEnough(newNumber)) {
numbers.push(newNumber);
}
}
return numbers;
};
const lefts = randNums(images.length, 0.05);
const tops = randNums(images.length, 0.05);
for (let index in images) {
const img = document.createElement("img");
img.setAttribute("src", images[index]);
img.setAttribute("alt", alts[index]);
let seedX = Math.random() * Math.random() * 100;
let seedY = Math.random() * Math.random() * 100;
img.setAttribute("seedX", seedX.toString());
img.setAttribute("seedY", seedY.toString());
const left = lefts[index];
const top = tops[index];
const z = (Math.abs(left) + Math.abs(top)) / 2;
const size = Math.random() * 5 + 9;
const range = { x: window.innerWidth * 0.7, y: window.innerHeight * 0.7 };
img.style.setProperty(
"left",
`${left * range.x + window.innerWidth / 2}px`,
);
img.style.setProperty("top", `${top * range.y + window.innerHeight / 2}px`);
img.style.setProperty("--translate-z", `${z * 3000}px`);
img.style.setProperty("inline-size", `${size}vmax`);
background.append(img);
}
};
const mobile = window.matchMedia("(hover: none) and (pointer: coarse)").matches;
if (!mobile) {
const root = document.documentElement;
const onMove = (ev: MouseEvent) => {
const rotateY = `${-(ev.clientX - window.innerWidth / 2) * 0.003}deg`;
const rotateX = `${(ev.clientY - window.innerHeight / 2) * 0.003}deg`;
root.style.setProperty("--rotate-x", rotateX);
root.style.setProperty("--rotate-y", rotateY);
};
document.addEventListener("mousemove", onMove);
}
window.addEventListener("load", () => {
background.setAttribute("loaded", "");
const noise = (t: number) => {
return Math.sin(2 * t) + Math.sin(Math.PI * t);
};
const toDomPrecision = (v: number) => {
return Math.round(v * 1e4) / 1e4;
};
const dpi = window.devicePixelRatio;
const moveImages = (t: number) => {
const background = document.getElementById("background")!;
const images = background.getElementsByTagName("img");
for (let i = 0; i < images.length; i++) {
const img = images[i];
let top = toDomPrecision(
Number(img.style.top.slice(0, img.style.top.length - 2)),
);
let left = toDomPrecision(
Number(img.style.left.slice(0, img.style.left.length - 2)),
);
top += (noise(Number(img.getAttribute("seedY")) + t) * 0.4) / dpi; // move faster on lower-res displays to improve jitter
left += (noise(Number(img.getAttribute("seedX")) + t) * 0.4) / dpi;
img.style.setProperty("top", `${top}px`);
img.style.setProperty("left", `${left}px`);
}
t += 0.0005;
window.requestAnimationFrame(moveImages.bind(this, t));
};
if (!prefersReducedMotion) {
moveImages(0);
}
});
setImages();