change snowflakes

This commit is contained in:
Nomi Nonsense (Nonszy) 2025-12-26 17:55:35 +07:00
parent 32e609ad71
commit 1215f2f987
7 changed files with 106 additions and 67 deletions

View File

@ -6,8 +6,7 @@ const nextConfig = {
remotePatterns: [ remotePatterns: [
{ {
protocol: 'https', protocol: 'https',
hostname: 'media.tenor.com', hostname: 'media.tenor.com'
pathname: '/1BCeG1aTiBAAAAAd/temptation-stairway-ena.gif'
} }
] ]
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -191,7 +191,7 @@ export const FakeRelativeWindow = ({
{/* Main window */} {/* Main window */}
<div <div
className={clsx("md:border bg-background border-primary", withAnim && animation.window)} className={clsx("md:border bg-background bg-opacity-50 border-primary", withAnim && animation.window)}
style={{ style={{
transform: `translate(${currentWindow.offset.x}px, ${currentWindow.offset.y}px)` transform: `translate(${currentWindow.offset.x}px, ${currentWindow.offset.y}px)`
}} }}

View File

@ -2,7 +2,7 @@
import { getEvent } from '@/lib/utils'; import { getEvent } from '@/lib/utils';
import clsx from 'clsx'; import clsx from 'clsx';
import Image from 'next/image'; import NextImage from 'next/image';
import { ReactNode, useEffect, useRef, useState } from 'react'; import { ReactNode, useEffect, useRef, useState } from 'react';
interface Snowflake { interface Snowflake {
@ -13,12 +13,15 @@ interface Snowflake {
sway: number; sway: number;
swayOffset: number; swayOffset: number;
opacity: number; opacity: number;
rotation: number;
rotationSpeed: number;
} }
interface ChristmasProps { interface ChristmasProps {
left: number; left: number;
top: number; top: number;
size: number; size: number;
img: string;
className?: string; className?: string;
flip?: boolean; flip?: boolean;
absolute?: boolean; absolute?: boolean;
@ -31,9 +34,10 @@ export const ChristmasExclusive = ({ children }: { children: ReactNode }) => {
return null; return null;
} }
export const ChristmasHat: React.FC<ChristmasProps> = ({ export const ChristmasProperty: React.FC<ChristmasProps> = ({
left, left,
top, top,
img,
size, size,
className, className,
flip flip
@ -46,12 +50,13 @@ export const ChristmasHat: React.FC<ChristmasProps> = ({
left, top left, top
}} }}
> >
<Image <NextImage
className='pointer-events-none' className='pointer-events-none'
src={'/images/event_santahat01.png'} src={img}
alt='Santa Hat' alt='Christmas prop'
height={size} height={size}
width={size} width={size}
unoptimized={img.slice(img.length - 3, img.length) == 'gif'}
/> />
</div> </div>
</ChristmasExclusive> </ChristmasExclusive>
@ -63,8 +68,8 @@ function SnowfallRawBackground() {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const snowflakesRef = useRef<Snowflake[]>([]); const snowflakesRef = useRef<Snowflake[]>([]);
const animationFrameRef = useRef<number>(0); const animationFrameRef = useRef<number>(0);
const imageRef = useRef<HTMLImageElement | null>(null);
// Update dimensions on resize
useEffect(() => { useEffect(() => {
const updateDimensions = () => { const updateDimensions = () => {
setDimensions({ setDimensions({
@ -80,18 +85,26 @@ function SnowfallRawBackground() {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!canvasRef.current) return;
const canvas = canvasRef.current; const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) return; if (!ctx) return;
canvas.width = dimensions.width; canvas.width = dimensions.width;
canvas.height = dimensions.height; canvas.height = dimensions.height;
// Load the snowflake image using a plain Image so we can draw it to canvas reliably
const img = new Image();
img.src = '/images/event_snowflake.png';
let mounted = true;
const start = () => {
if (!mounted) return;
imageRef.current = img;
const createSnowflake = (init?: boolean): Snowflake => { const createSnowflake = (init?: boolean): Snowflake => {
let posy = -10; let posy = -10;
let radius = Math.random() * 4 + 2; let radius = Math.random() * 18 + 10;
let speed = Math.random() * 1 + 0.5; let speed = Math.random() * 1 + 0.5;
let sway = Math.random() * 0.5 + 0.2; let sway = Math.random() * 0.5 + 0.2;
@ -112,13 +125,14 @@ function SnowfallRawBackground() {
speed, speed,
sway, sway,
swayOffset: Math.random() * Math.PI * 2, swayOffset: Math.random() * Math.PI * 2,
opacity: Math.random() * 0.5 + 0.5, opacity: Math.random() * 0.5 + 0.2,
rotation: Math.random() * Math.PI * 2,
rotationSpeed: (Math.random() - 0.5) * 0.02,
} }
}; };
const snowflakes: Snowflake[] = []; const snowflakes: Snowflake[] = [];
for (let i = 0; i < 200; i++) { for (let i = 0; i < 80; i++) {
snowflakes.push(createSnowflake(true)); snowflakes.push(createSnowflake(true));
} }
snowflakesRef.current = snowflakes; snowflakesRef.current = snowflakes;
@ -129,27 +143,47 @@ function SnowfallRawBackground() {
snowflakesRef.current.forEach((flake, index) => { snowflakesRef.current.forEach((flake, index) => {
flake.y += flake.speed; flake.y += flake.speed;
flake.x += Math.sin(flake.swayOffset + flake.y * 0.02) * flake.sway; flake.x += Math.sin(flake.swayOffset + flake.y * 0.02) * flake.sway;
flake.rotation += flake.rotationSpeed;
const shrink = dimensions.height < 768 ? 0.001 : 0.005 const shrink = dimensions.height < 768 ? 0.005 : 0.01;
flake.radius = Math.max(0, flake.radius - shrink); flake.radius = Math.max(2, flake.radius - shrink);
if (flake.y > dimensions.height || flake.radius <= 0.5) { if (flake.y > dimensions.height || flake.radius <= 0.5) {
snowflakesRef.current[index] = createSnowflake(); snowflakesRef.current[index] = createSnowflake();
return; return;
} }
ctx.beginPath(); ctx.save();
ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2); ctx.globalAlpha = flake.opacity;
ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity})`; ctx.translate(flake.x, flake.y);
ctx.fill(); ctx.rotate(flake.rotation);
ctx.drawImage(
img,
-flake.radius / 2,
-flake.radius / 2,
flake.radius,
flake.radius
);
ctx.restore();
}); });
animationFrameRef.current = requestAnimationFrame(animate); animationFrameRef.current = requestAnimationFrame(animate);
}; };
animationFrameRef.current = requestAnimationFrame(animate); animationFrameRef.current = requestAnimationFrame(animate);
};
return () => cancelAnimationFrame(animationFrameRef.current); if (img.complete) start();
else img.onload = start;
return () => {
mounted = false;
cancelAnimationFrame(animationFrameRef.current);
img.onload = null;
imageRef.current = null;
};
}, [dimensions]); }, [dimensions]);
return ( return (
@ -157,6 +191,7 @@ function SnowfallRawBackground() {
ref={canvasRef} ref={canvasRef}
className="fixed top-0 left-0 w-full h-full pointer-events-none" className="fixed top-0 left-0 w-full h-full pointer-events-none"
style={{ zIndex: 0 }} style={{ zIndex: 0 }}
aria-hidden="true"
/> />
); );
} }

View File

@ -3,7 +3,7 @@ import { FloatingLabel } from "@/components/floating-label";
import { FakeRelativeWindow, RestoreWindowsButton } from "./client-windows"; import { FakeRelativeWindow, RestoreWindowsButton } from "./client-windows";
import Image from "next/image" import Image from "next/image"
import Link from "next/link"; import Link from "next/link";
import { ChristmasHat } from "./events/christmas"; import { ChristmasProperty } from "./events/christmas";
export const FakeWindow = ({ export const FakeWindow = ({
windowText, children windowText, children
@ -12,7 +12,12 @@ export const FakeWindow = ({
children: React.ReactNode children: React.ReactNode
}) => ( }) => (
<div className="relative md:bg-background mx-auto w-[480px] md:w-[520px] md:border border-primary z-10"> <div className="relative md:bg-background mx-auto w-[480px] md:w-[520px] md:border border-primary z-10">
<ChristmasHat size={180} left={-60} top={-80} /> <ChristmasProperty
img="/images/event_santahat1.png"
size={180}
left={-60}
top={-80}
/>
<div className="p-1 pb-0"> <div className="p-1 pb-0">
<div className="hidden md:flex bg-primary p-2 justify-between text-background"> <div className="hidden md:flex bg-primary p-2 justify-between text-background">
<div className="ms-1 pointer-events-none"> <div className="ms-1 pointer-events-none">
@ -48,7 +53,7 @@ export const HomeWindows = () => (
> >
<FloatingLabel placeholder="This is Nola, my OC :3"> <FloatingLabel placeholder="This is Nola, my OC :3">
<div className="relative"> <div className="relative">
<ChristmasHat size={150} top={-40} left={70} flip /> <ChristmasProperty img="/images/event_santahat1.png" size={150} top={-40} left={70} flip />
<Image <Image
className="" className=""
alt="Nola" alt="Nola"
@ -93,13 +98,13 @@ export const HomeWindows = () => (
/> />
</FakeRelativeWindow> </FakeRelativeWindow>
<FakeRelativeWindow <FakeRelativeWindow
windowText="coral_cupcake.mkv" windowText="ena_spin.obj"
className="-right-[85%] top-[440px] z-10" className="-right-[85%] top-[440px] z-10"
draggable draggable
> >
<Image <Image
alt="Coral Cupcake" alt="Coral Cupcake"
src="https://media1.tenor.com/m/N5K-4AWj8QcAAAAC/coral-glasses-cupcake.gif" src="https://media.tenor.com/Uv-PLe5GIe0AAAAi/gyaruface.gif"
width={240} width={240}
height={200} height={200}
quality={10} quality={10}