feat: star background
This commit is contained in:
148
assets/app.js
148
assets/app.js
@@ -46,116 +46,56 @@
|
||||
function makeSpace() {
|
||||
var space = document.createElement("div");
|
||||
space.className = "space";
|
||||
var w = window.innerWidth;
|
||||
var h = window.innerHeight;
|
||||
space.setAttribute("aria-hidden", "true");
|
||||
var small = window.innerWidth < 700;
|
||||
var tints = ["#ffffff", "#ffffff", "#cfe0ff", "#bcd0ff", "#ffe6c8", "#a8f0d2"];
|
||||
|
||||
var starCount = w < 700 ? 80 : 150;
|
||||
var stars = [];
|
||||
for (var i = 0; i < starCount; i++) {
|
||||
var s = document.createElement("div");
|
||||
s.className = "space__star";
|
||||
var size = 0.8 + Math.random() * 1.6;
|
||||
var base = 0.2 + Math.random() * 0.55;
|
||||
s.style.width = size + "px";
|
||||
s.style.height = size + "px";
|
||||
s.style.boxShadow = "0 0 " + (size * 2) + "px rgba(255,255,255," + (base * 0.5) + ")";
|
||||
space.appendChild(s);
|
||||
stars.push({
|
||||
el: s,
|
||||
x: Math.random() * w,
|
||||
y: Math.random() * h,
|
||||
vx: (Math.random() - 0.5) * 1.4,
|
||||
vy: (Math.random() - 0.5) * 1.4,
|
||||
base: base,
|
||||
phase: Math.random() * Math.PI * 2,
|
||||
twinkle: 0.3 + Math.random() * 0.5
|
||||
});
|
||||
function rnd(a, b) { return a + Math.random() * (b - a); }
|
||||
|
||||
function layer(count, cls) {
|
||||
var box = document.createElement("div");
|
||||
box.className = "space__layer " + cls;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var s = document.createElement("div");
|
||||
var r = Math.random();
|
||||
var size = r < 0.7 ? rnd(1, 1.6) : r < 0.94 ? rnd(1.8, 2.4) : rnd(2.8, 3.6);
|
||||
var big = r >= 0.94;
|
||||
s.className = "space__star";
|
||||
s.style.left = rnd(0, 100).toFixed(2) + "%";
|
||||
s.style.top = rnd(0, 100).toFixed(2) + "%";
|
||||
s.style.width = size.toFixed(1) + "px";
|
||||
s.style.height = size.toFixed(1) + "px";
|
||||
s.style.setProperty("--c", tints[(Math.random() * tints.length) | 0]);
|
||||
s.style.setProperty("--o", (big ? rnd(0.8, 1) : rnd(0.4, 0.85)).toFixed(2));
|
||||
s.style.setProperty("--g", (size * (big ? 3 : 1.5)).toFixed(1) + "px");
|
||||
s.style.setProperty("--t", rnd(3, 8).toFixed(1) + "s");
|
||||
s.style.setProperty("--d", (-rnd(0, 8)).toFixed(1) + "s");
|
||||
box.appendChild(s);
|
||||
}
|
||||
space.appendChild(box);
|
||||
}
|
||||
|
||||
var nebulae = [
|
||||
{ x: 0.18, y: 0.30, rx: 38, ry: 22, angle: -20, c1: "120,150,255", c2: "80,200,200", strength: 0.5 },
|
||||
{ x: 0.78, y: 0.22, rx: 30, ry: 44, angle: 160, c1: "180,120,255", c2: "240,150,120", strength: 0.4 },
|
||||
{ x: 0.55, y: 0.78, rx: 46, ry: 26, angle: 70, c1: "150,210,255", c2: "120,240,180", strength: 0.45 }
|
||||
];
|
||||
layer(small ? 50 : 90, "space__layer--far");
|
||||
layer(small ? 22 : 40, "space__layer--near");
|
||||
|
||||
nebulae.forEach(function (n, idx) {
|
||||
var el = document.createElement("div");
|
||||
el.className = "space__nebula";
|
||||
el.style.width = (n.rx * 2.6) + "%";
|
||||
el.style.height = (n.ry * 2.6) + "%";
|
||||
el.style.left = (n.x * 100 - n.rx * 1.3) + "%";
|
||||
el.style.top = (n.y * 100 - n.ry * 1.3) + "%";
|
||||
el.style.background =
|
||||
"radial-gradient(ellipse at center, rgba(" + n.c1 + "," + (0.22 * n.strength) +
|
||||
"), rgba(" + n.c2 + "," + (0.16 * n.strength) + "), transparent 70%)";
|
||||
n.el = el;
|
||||
n.seed = idx * 19.1;
|
||||
n.amp = 1.6;
|
||||
space.appendChild(el);
|
||||
});
|
||||
if (!reduce) {
|
||||
var aim = function (m) {
|
||||
m.style.left = rnd(35, 105).toFixed(1) + "%";
|
||||
m.style.top = rnd(-8, 45).toFixed(1) + "%";
|
||||
};
|
||||
for (var k = 0; k < (small ? 2 : 3); k++) {
|
||||
var m = document.createElement("div");
|
||||
m.className = "space__meteor";
|
||||
m.style.setProperty("--t", rnd(9, 17).toFixed(1) + "s");
|
||||
m.style.setProperty("--d", rnd(1, 9).toFixed(1) + "s");
|
||||
m.style.setProperty("--a", rnd(138, 152).toFixed(0) + "deg");
|
||||
aim(m);
|
||||
m.addEventListener("animationiteration", function (e) { aim(e.target); });
|
||||
space.appendChild(m);
|
||||
}
|
||||
}
|
||||
|
||||
document.body.appendChild(space);
|
||||
|
||||
function place(star) {
|
||||
star.el.style.transform =
|
||||
"translate3d(" + star.x.toFixed(1) + "px," + star.y.toFixed(1) + "px,0)";
|
||||
}
|
||||
|
||||
function placeNebula(n, t) {
|
||||
var dx = Math.sin(t * 0.25 + n.seed) * n.amp;
|
||||
var dy = Math.cos(t * 0.20 + n.seed * 0.7) * n.amp;
|
||||
n.el.style.transform =
|
||||
"translate3d(" + dx.toFixed(2) + "vw," + dy.toFixed(2) + "vh,0) rotate(" + n.angle + "deg)";
|
||||
n.el.style.opacity = 0.09 + 0.03 * Math.sin(t * 0.4 + n.seed);
|
||||
}
|
||||
|
||||
if (reduce) {
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
place(stars[k]);
|
||||
stars[k].el.style.opacity = stars[k].base;
|
||||
}
|
||||
nebulae.forEach(function (n) { placeNebula(n, 0); });
|
||||
window.addEventListener("resize", function () {
|
||||
w = window.innerWidth;
|
||||
h = window.innerHeight;
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
if (stars[k].x > w) stars[k].x = Math.random() * w;
|
||||
if (stars[k].y > h) stars[k].y = Math.random() * h;
|
||||
place(stars[k]);
|
||||
}
|
||||
}, { passive: true });
|
||||
return;
|
||||
}
|
||||
|
||||
var last = performance.now();
|
||||
function frame(now) {
|
||||
var dt = Math.min((now - last) / 1000, 0.1);
|
||||
last = now;
|
||||
var t = now * 0.00005;
|
||||
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
var st = stars[k];
|
||||
st.x += st.vx * dt;
|
||||
st.y += st.vy * dt;
|
||||
if (st.x < -4) st.x += w + 8;
|
||||
else if (st.x > w + 4) st.x -= w + 8;
|
||||
if (st.y < -4) st.y += h + 8;
|
||||
else if (st.y > h + 4) st.y -= h + 8;
|
||||
place(st);
|
||||
st.el.style.opacity =
|
||||
st.base * (0.65 + 0.35 * Math.sin(t * st.twinkle * 12 + st.phase));
|
||||
}
|
||||
|
||||
for (var j = 0; j < nebulae.length; j++) placeNebula(nebulae[j], t);
|
||||
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
requestAnimationFrame(frame);
|
||||
|
||||
window.addEventListener("resize", function () {
|
||||
w = window.innerWidth;
|
||||
h = window.innerHeight;
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
106
assets/style.css
106
assets/style.css
@@ -72,30 +72,118 @@ body {
|
||||
|
||||
.space {
|
||||
position: fixed;
|
||||
inset: -5% -5% -5% -5%;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
background:
|
||||
radial-gradient(55% 45% at 85% 6%, rgba(111, 227, 176, 0.07), transparent 70%),
|
||||
radial-gradient(60% 50% at 8% 92%, rgba(110, 130, 255, 0.08), transparent 70%);
|
||||
}
|
||||
|
||||
.space::before,
|
||||
.space::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
animation: nebula 50s ease-in-out infinite alternate;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.space::before {
|
||||
top: -14vmax;
|
||||
left: -18vmax;
|
||||
width: 75vmax;
|
||||
height: 55vmax;
|
||||
background: radial-gradient(closest-side, rgba(120, 140, 255, 0.17), rgba(80, 200, 210, 0.07) 55%, transparent);
|
||||
}
|
||||
|
||||
.space::after {
|
||||
right: -22vmax;
|
||||
bottom: -26vmax;
|
||||
width: 70vmax;
|
||||
height: 65vmax;
|
||||
background: radial-gradient(closest-side, rgba(180, 120, 255, 0.15), rgba(240, 150, 120, 0.06) 55%, transparent);
|
||||
animation-duration: 64s;
|
||||
animation-direction: alternate-reverse;
|
||||
}
|
||||
|
||||
.space__layer {
|
||||
position: absolute;
|
||||
inset: -4%;
|
||||
will-change: transform;
|
||||
animation: drift var(--dur, 240s) linear infinite alternate;
|
||||
}
|
||||
|
||||
.space__layer--far {
|
||||
--dur: 300s;
|
||||
--dx: -1.5%;
|
||||
--dy: 2%;
|
||||
}
|
||||
|
||||
.space__layer--near {
|
||||
--dur: 180s;
|
||||
--dx: -3%;
|
||||
--dy: 3.5%;
|
||||
}
|
||||
|
||||
.space__star {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
background: #ffffff;
|
||||
background: var(--c, #fff);
|
||||
box-shadow: 0 0 var(--g, 3px) var(--c, #fff);
|
||||
opacity: var(--o, 0.6);
|
||||
animation: twinkle var(--t, 5s) ease-in-out var(--d, 0s) infinite;
|
||||
}
|
||||
|
||||
.space__nebula {
|
||||
.space__meteor {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
will-change: transform, opacity;
|
||||
width: clamp(90px, 12vmax, 170px);
|
||||
height: 1.5px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.95));
|
||||
box-shadow: 0 0 6px rgba(190, 215, 255, 0.5);
|
||||
opacity: 0;
|
||||
animation: meteor var(--t, 12s) linear var(--d, 4s) infinite;
|
||||
}
|
||||
|
||||
@keyframes nebula {
|
||||
from { transform: translate3d(0, 0, 0) scale(1); }
|
||||
to { transform: translate3d(4vw, 3vh, 0) scale(1.1); }
|
||||
}
|
||||
|
||||
@keyframes drift {
|
||||
to { transform: translate3d(var(--dx, -2%), var(--dy, 3%), 0); }
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: var(--o, 0.6); }
|
||||
50% { opacity: calc(var(--o, 0.6) * 0.3); }
|
||||
}
|
||||
|
||||
@keyframes meteor {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: rotate(var(--a, 145deg)) translateX(0);
|
||||
}
|
||||
1.5% {
|
||||
opacity: 0.9;
|
||||
}
|
||||
7%, 100% {
|
||||
opacity: 0;
|
||||
transform: rotate(var(--a, 145deg)) translateX(55vmax);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.space {
|
||||
.space::before,
|
||||
.space::after,
|
||||
.space__layer,
|
||||
.space__star {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.space__meteor {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user