snowflake rewrite

This commit is contained in:
z0x 2024-11-17 01:11:58 -05:00
parent 39c53b1bd1
commit b2b7360a65
11 changed files with 428 additions and 361 deletions

12
src/css/app.css Normal file
View file

@ -0,0 +1,12 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
@font-face {
font-family: "sf-pro";
font-style: normal;
font-display: swap;
src: url(/src/fonts/SF-Pro.woff2) format("woff2");
}
}

View file

@ -1,24 +0,0 @@
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes snowfall {
0% {
transform: translateY(-10vh);
}
100% {
transform: translateY(130vh);
}
}
.snowflake {
background: white;
border-radius: 50%;
position: fixed;
top: -5vh;
animation: snowfall infinite;
opacity: 0.1;
}

BIN
src/fonts/SF-Pro.woff2 Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

12
src/js/index.ts Normal file
View file

@ -0,0 +1,12 @@
import { animate, stagger } from "motion";
const elements = document.querySelectorAll("img, h1");
animate(
elements,
{ opacity: [0, 1] },
{
duration: 0.6,
delay: stagger(0.6, { startDelay: 0.2 }),
ease: "easeIn",
},
);

View file

@ -1,27 +1,79 @@
function createSnowflakes() {
const numSnowflakes = 50;
const maxSize = 0.2;
const maxTranslate = 10;
const container = document.getElementById('snowflake-container');
function randomBetween(min, max) {
return (Math.random() * max) + min;
class SnowEffect {
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D;
private flakes: Array<[number, number, number, number, number]>; // [x, y, radius, drop, sway]
constructor(flakeCount = 320) {
this.canvas = document.createElement("canvas");
this.ctx = this.canvas.getContext("2d")!;
this.flakes = [];
this.initCanvas();
this.initFlakes(flakeCount);
this.animate = this.animate.bind(this);
window.addEventListener("resize", () => this.updateCanvasSize());
requestAnimationFrame(this.animate);
}
if (container) {
for (let i = 0; i < numSnowflakes; i++) {
let randomSize = randomBetween(5, 25) + "px";
let randomLeft = randomBetween(0, window.innerWidth) + "px";
let randomDuration = randomBetween(3, 10);
const snowflake = document.createElement('div');
snowflake.classList.add('snowflake');
snowflake.style.width = randomSize;
snowflake.style.height = randomSize;
snowflake.style.left = randomLeft;
snowflake.style.animationDuration = randomDuration + "s";
snowflake.style.animationDelay = randomBetween(0, 5) + "s";
private initCanvas(): void {
this.canvas.style.cssText =
"position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:999";
document.body.appendChild(this.canvas);
this.updateCanvasSize();
}
container.appendChild(snowflake);
private updateCanvasSize(): void {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
private initFlakes(count: number): void {
const { width, height } = this.canvas;
this.flakes = Array.from({ length: count }, () => [
Math.random() * width, // x
Math.random() * height, // y
Math.random() * 1.75 + 0.25, // radius
Math.random() * 1.5 + 0.5, // drop speed
Math.random() * 0.6 - 0.3, // sway
]);
}
private animate(): void {
const { width, height } = this.canvas;
// Clear canvas
this.ctx.clearRect(0, 0, width, height);
// Draw flakes
this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
this.ctx.beginPath();
// Update and draw flakes
for (const flake of this.flakes) {
// Update position
flake[1] += flake[3]; // y += drop
flake[0] += flake[4]; // x += sway
// Wrap horizontally
if (flake[0] > width) flake[0] -= width;
else if (flake[0] < 0) flake[0] += width;
// Reset when below screen
if (flake[1] > height) {
flake[1] = -flake[2];
flake[0] = Math.random() * width;
}
// Draw flake
this.ctx.moveTo(flake[0], flake[1]);
this.ctx.arc(flake[0], flake[1], flake[2], 0, Math.PI * 2);
}
this.ctx.fill();
requestAnimationFrame(this.animate);
}
}
createSnowflakes();
// start
new SnowEffect();

View file

@ -1,5 +1,5 @@
---
import "./src/css/snowflake.css";
import "./src/css/app.css";
---
<html lang="en-us">
@ -12,14 +12,15 @@ import "./src/css/snowflake.css";
<link rel="icon" type="image/png" sizes="192x192" href="/src/img/logo_bg.svg" />
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="/src/img/logo_bg.svg" />
</head>
<body class="bg-cover bg-[url('/src/img/gradient.webp')] text-white overflow-hidden">
<body class="bg-gradient-to-b from-neutral-700 via-neutral-900 to-neutral-950 text-white overflow-hidden">
<div class="flex items-center justify-center min-h-screen">
<div class="bg-[rgba(11,11,11,0.6)] aspect-square rounded-3xl border-2 border-white flex flex-col items-center justify-center w-full h-full max-w-[60vmin] max-h-[60vmin] md:max-w-[35vmin] md:max-h-[35vmin]">
<img class="w-2/3" src="/src/img/logo.svg" alt="logo" />
<h1 class="text-4xl">z0x</h1>
<div class="bg-black bg-opacity-40 aspect-square rounded-xl flex flex-col items-center justify-center w-full h-full max-w-[60vmin] max-h-[60vmin] md:max-w-[35vmin] md:max-h-[35vmin]">
<img class="w-2/3 opacity-0" src="/src/img/logo.svg" alt="logo" />
<h1 class="text-4xl opacity-0 font-sfpro font-semibold">z0x</h1>
</div>
</div>
<div id="snowflake-container"></div>
<script src="/src/js/snowflakes.js"></script>
<script src="/src/js/snowflakes.ts"></script>
<script src="/src/js/index.ts"></script>
</body>
</html>