feat: add background star renderer

This commit is contained in:
2026-04-10 19:50:54 +07:00 Unverified
parent 85919fd545
commit 26ce84eca4
7 changed files with 85 additions and 4 deletions
+4 -2
View File
@@ -1,8 +1,9 @@
import Image from "next/image";
import { ViewTransition } from "react";
import { Toaster } from "sonner";
import Background from "#/bg.jpg";
import Background from "#/bg.webp";
import Image from "@/components/image";
import { SentryDevToolbar } from "@/components/sentry";
import { StarsRenderer } from "@/components/stars";
import Providers, { VersionCheck } from "../client";
import { Navbar } from "./navbar";
@@ -18,6 +19,7 @@ export default async function UiLayout({
alt="Background"
className="z-[-1] opacity-40 object-cover fixed top-0 left-0 w-full h-fit min-h-dvh"
/>
<StarsRenderer />
<Providers>
<ViewTransition>{children}</ViewTransition>
<VersionCheck />
+1 -1
View File
@@ -13,7 +13,7 @@ import {
import Link from "next/link";
import { useEffect, useState } from "react";
import Dottore from "#/assets/dottore.webp";
import Background from "#/bg.jpg";
import Background from "#/bg.webp";
import Image from "@/components/image";
import { SimpleTooltip } from "@/components/tooltip";
import { Button } from "@/components/ui/button";
+1 -1
View File
@@ -4,7 +4,7 @@ import { Activity, Home } from "lucide-react";
import Link from "next/link";
import { useEffect, useState } from "react";
import Dottore from "#/assets/dottore.webp";
import Background from "#/bg.jpg";
import Background from "#/bg.webp";
import Image from "@/components/image";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
+79
View File
@@ -0,0 +1,79 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
export function StarsRenderer() {
const cv = useRef<HTMLCanvasElement | null>(null);
const [loaded, setLoaded] = useState(false);
useEffect(() => {
if (!cv.current) return;
const canvas = cv.current;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const stars: {
x: number;
y: number;
r: number;
alpha: number;
speed: number;
}[] = [];
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resize();
window.addEventListener("resize", resize);
for (let i = 0; i < Math.min(1000, canvas.width); i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
r: Math.random() * 1.5,
alpha: Math.random(),
speed: Math.random() * 0.04,
});
}
function draw() {
if (!ctx) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const s of stars) {
s.alpha += s.speed;
if (s.alpha > 1 || s.alpha < 0) {
s.speed *= -1;
}
ctx.globalAlpha = s.alpha;
ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
ctx.fillStyle = "white";
ctx.fill();
}
requestAnimationFrame(dummy);
}
function dummy() {
requestAnimationFrame(draw);
}
draw();
setLoaded(true);
}, []);
return (
<canvas
ref={cv}
className={cn(
"z-[-1] object-cover fixed top-0 left-0 w-full h-fit min-h-dvh mask-[url('/mask.webp')] mask-cover mask-center mask-no-repeat transition-opacity duration-5000 opacity-0",
loaded && "opacity-40",
)}
></canvas>
);
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 808 KiB