add cursor follow animation

This commit is contained in:
Kentai Radiquum 2025-02-13 11:37:48 +05:00
parent ad5167e805
commit 2c518c17a3
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
4 changed files with 333 additions and 19 deletions

View file

@ -1,5 +1,20 @@
@import "tailwindcss"; @import "tailwindcss";
@layer utilities {
/* Chrome, Safari and Opera */
.scrollbar-hidden::-webkit-scrollbar {
display: none;
}
.scrollbar-hidden {
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
}
}
.ubuntu-regular { .ubuntu-regular {
font-family: "Ubuntu", serif; font-family: "Ubuntu", serif;
font-weight: 400; font-weight: 400;
@ -19,10 +34,7 @@
font-style: normal; font-style: normal;
} }
body { .background-grid {
position: relative;
/* Create the dots */
background-image: background-image:
radial-gradient(circle at 1px 1px, #33333366 1px, transparent 0), radial-gradient(circle at 1px 1px, #33333366 1px, transparent 0),
linear-gradient(to right, #33333366 1px, transparent 1px), linear-gradient(to right, #33333366 1px, transparent 1px),

View file

@ -518,12 +518,18 @@
} }
} }
@layer utilities { @layer utilities {
.collapse {
visibility: collapse;
}
.invisible { .invisible {
visibility: hidden; visibility: hidden;
} }
.absolute { .absolute {
position: absolute; position: absolute;
} }
.fixed {
position: fixed;
}
.relative { .relative {
position: relative; position: relative;
} }
@ -542,6 +548,9 @@
.-z-10 { .-z-10 {
z-index: calc(10 * -1); z-index: calc(10 * -1);
} }
.-z-50 {
z-index: calc(50 * -1);
}
.col-\[1\] { .col-\[1\] {
grid-column: 1; grid-column: 1;
} }
@ -608,6 +617,9 @@
.block { .block {
display: block; display: block;
} }
.contents {
display: contents;
}
.flex { .flex {
display: flex; display: flex;
} }
@ -620,12 +632,24 @@
.inline { .inline {
display: inline; display: inline;
} }
.inline-flex {
display: inline-flex;
}
.list-item {
display: list-item;
}
.table {
display: table;
}
.aspect-square { .aspect-square {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
.aspect-video { .aspect-video {
aspect-ratio: var(--aspect-video); aspect-ratio: var(--aspect-video);
} }
.h-0 {
height: calc(var(--spacing) * 0);
}
.h-4 { .h-4 {
height: calc(var(--spacing) * 4); height: calc(var(--spacing) * 4);
} }
@ -641,24 +665,48 @@
.h-\[114px\] { .h-\[114px\] {
height: 114px; height: 114px;
} }
.h-\[256px\] {
height: 256px;
}
.h-full { .h-full {
height: 100%; height: 100%;
} }
.max-h-\[105\%\] {
max-height: 105%;
}
.max-h-\[110dvh\] {
max-height: 110dvh;
}
.max-h-\[512px\] { .max-h-\[512px\] {
max-height: 512px; max-height: 512px;
} }
.max-h-full {
max-height: 100%;
}
.min-h-\[140dvh\] {
min-height: 140dvh;
}
.min-h-\[438px\] { .min-h-\[438px\] {
min-height: 438px; min-height: 438px;
} }
.w-0 {
width: calc(var(--spacing) * 0);
}
.w-4 { .w-4 {
width: calc(var(--spacing) * 4); width: calc(var(--spacing) * 4);
} }
.w-6 { .w-6 {
width: calc(var(--spacing) * 6); width: calc(var(--spacing) * 6);
} }
.w-8 {
width: calc(var(--spacing) * 8);
}
.w-\[114px\] { .w-\[114px\] {
width: 114px; width: 114px;
} }
.w-\[256px\] {
width: 256px;
}
.w-full { .w-full {
width: 100%; width: 100%;
} }
@ -674,9 +722,15 @@
.max-w-\[1210px\] { .max-w-\[1210px\] {
max-width: 1210px; max-width: 1210px;
} }
.flex-shrink {
flex-shrink: 1;
}
.flex-shrink-0 { .flex-shrink-0 {
flex-shrink: 0; flex-shrink: 0;
} }
.border-collapse {
border-collapse: collapse;
}
.origin-center { .origin-center {
transform-origin: center; transform-origin: center;
} }
@ -704,9 +758,15 @@
--tw-scale-z: 150%; --tw-scale-z: 150%;
scale: var(--tw-scale-x) var(--tw-scale-y); scale: var(--tw-scale-x) var(--tw-scale-y);
} }
.transform {
transform: var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y);
}
.animate-ping { .animate-ping {
animation: var(--animate-ping); animation: var(--animate-ping);
} }
.resize {
resize: both;
}
.grid-cols-1 { .grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr)); grid-template-columns: repeat(1, minmax(0, 1fr));
} }
@ -764,8 +824,8 @@
.overflow-hidden { .overflow-hidden {
overflow: hidden; overflow: hidden;
} }
.overflow-x-hidden { .overflow-y-auto {
overflow-x: hidden; overflow-y: auto;
} }
.rounded-full { .rounded-full {
border-radius: calc(infinity * 1px); border-radius: calc(infinity * 1px);
@ -834,6 +894,12 @@
.py-8 { .py-8 {
padding-block: calc(var(--spacing) * 8); padding-block: calc(var(--spacing) * 8);
} }
.pb-8 {
padding-bottom: calc(var(--spacing) * 8);
}
.pb-16 {
padding-bottom: calc(var(--spacing) * 16);
}
.text-right { .text-right {
text-align: right; text-align: right;
} }
@ -871,6 +937,20 @@
.text-white { .text-white {
color: var(--color-white); color: var(--color-white);
} }
.underline {
text-decoration-line: underline;
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.backdrop-filter {
-webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
}
.transition { .transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter; transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@ -955,6 +1035,11 @@
padding-block: calc(var(--spacing) * 14); padding-block: calc(var(--spacing) * 14);
} }
} }
.sm\:pb-14 {
@media (width >= 40rem) {
padding-bottom: calc(var(--spacing) * 14);
}
}
.sm\:text-base { .sm\:text-base {
@media (width >= 40rem) { @media (width >= 40rem) {
font-size: var(--text-base); font-size: var(--text-base);
@ -992,6 +1077,11 @@
padding-block: calc(var(--spacing) * 0); padding-block: calc(var(--spacing) * 0);
} }
} }
.md\:pb-0 {
@media (width >= 48rem) {
padding-bottom: calc(var(--spacing) * 0);
}
}
.md\:text-\[32px\] { .md\:text-\[32px\] {
@media (width >= 48rem) { @media (width >= 48rem) {
font-size: 32px; font-size: 32px;
@ -1070,6 +1160,15 @@
} }
} }
} }
@layer utilities {
.scrollbar-hidden::-webkit-scrollbar {
display: none;
}
.scrollbar-hidden {
scrollbar-width: none;
-ms-overflow-style: none;
}
}
.ubuntu-regular { .ubuntu-regular {
font-family: "Ubuntu", serif; font-family: "Ubuntu", serif;
font-weight: 400; font-weight: 400;
@ -1086,8 +1185,7 @@
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
} }
body { .background-grid {
position: relative;
background-image: radial-gradient(circle at 1px 1px, #33333366 1px, transparent 0), linear-gradient(to right, #33333366 1px, transparent 1px), linear-gradient(to bottom, #33333366 1px, transparent 1px); background-image: radial-gradient(circle at 1px 1px, #33333366 1px, transparent 0), linear-gradient(to right, #33333366 1px, transparent 1px), linear-gradient(to bottom, #33333366 1px, transparent 1px);
background-size: 20px 20px; background-size: 20px 20px;
background-position: 0 0, 0 0, 0 0; background-position: 0 0, 0 0, 0 0;
@ -1134,6 +1232,31 @@ body {
inherits: false; inherits: false;
initial-value: 1; initial-value: 1;
} }
@property --tw-rotate-x {
syntax: "*";
inherits: false;
initial-value: rotateX(0);
}
@property --tw-rotate-y {
syntax: "*";
inherits: false;
initial-value: rotateY(0);
}
@property --tw-rotate-z {
syntax: "*";
inherits: false;
initial-value: rotateZ(0);
}
@property --tw-skew-x {
syntax: "*";
inherits: false;
initial-value: skewX(0);
}
@property --tw-skew-y {
syntax: "*";
inherits: false;
initial-value: skewY(0);
}
@property --tw-border-style { @property --tw-border-style {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
@ -1189,6 +1312,83 @@ body {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
} }
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-blur {
syntax: "*";
inherits: false;
}
@property --tw-brightness {
syntax: "*";
inherits: false;
}
@property --tw-contrast {
syntax: "*";
inherits: false;
}
@property --tw-grayscale {
syntax: "*";
inherits: false;
}
@property --tw-hue-rotate {
syntax: "*";
inherits: false;
}
@property --tw-invert {
syntax: "*";
inherits: false;
}
@property --tw-opacity {
syntax: "*";
inherits: false;
}
@property --tw-saturate {
syntax: "*";
inherits: false;
}
@property --tw-sepia {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-blur {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-brightness {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-contrast {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-grayscale {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-hue-rotate {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-invert {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-opacity {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-saturate {
syntax: "*";
inherits: false;
}
@property --tw-backdrop-sepia {
syntax: "*";
inherits: false;
}
@property --tw-duration { @property --tw-duration {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;

58
src/static/js/cursor.js Normal file
View file

@ -0,0 +1,58 @@
// Fields
let prim = document.getElementById("cursor-prim");
let seco = document.getElementById("cursor-sec");
let scroll = 0;
let sx,
px = (sx = window.innerWidth / 2);
let sy,
py = (sy = window.innerHeight / 2);
const base_speed = 128;
// Event listeners
// On mouse move
window.addEventListener("mousemove", (e) => {
// Primary position
(px = e.clientX), (py = e.clientY);
prim.style.top = `${py}px`;
prim.style.left = `${px}px`;
});
window.addEventListener("scroll", (e) => {
scroll = window.scrollY;
});
// Secondary render loop
let render = () => {
// Calculates delta value
if (!this.last) this.last = new Date().getTime();
let delta = (new Date().getTime() - this.last) / 16;
this.last = new Date().getTime();
console.log(scroll);
// Base speed, position difference,
// direction and distance
let dx = px - sx,
dy = py - sy;
let dir = Math.atan2(dy, dx);
let dis = Math.sqrt(dx * dx + dy * dy);
// Ease-out transition
let t = Math.min(dis / 500, 1);
let speed = base_speed * (t * t * (3.0 - 2.0 * t) * 0.94 + 0.06) * delta;
// Calculates new positions and dead zone
sx += Math.cos(dir) * speed;
sy += Math.sin(dir) * speed;
if (dis <= 4) {
sx = px;
sy = py;
}
// Sets position
seco.style.top = `${sy - 128 + scroll}px`;
seco.style.left = `${sx - 128}px`;
// Loops around
requestAnimationFrame(render);
};
render();

View file

@ -30,28 +30,72 @@ export default function Base({ children, isDev }: BaseProps) {
rel="stylesheet" rel="stylesheet"
></link> ></link>
<link rel="apple-touch-icon" sizes="180x180" href="/static/favicon/apple-touch-icon.png" /> <link
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon/favicon-32x32.png" /> rel="apple-touch-icon"
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon/favicon-16x16.png" /> sizes="180x180"
href="/static/favicon/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/favicon/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/static/favicon/favicon-16x16.png"
/>
<link rel="manifest" href="/static/favicon/site.webmanifest" /> <link rel="manifest" href="/static/favicon/site.webmanifest" />
<meta name="description" content="A tech non-company with a whole lot of wah—100% tech, 200% wah!" /> <meta
<meta name="keywords" content="wah.su, radiquum, invite-only, hosting" /> name="description"
content="A tech non-company with a whole lot of wah—100% tech, 200% wah!"
/>
<meta
name="keywords"
content="wah.su, radiquum, invite-only, hosting"
/>
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="https://home.wah.su/" /> <meta name="twitter:site" content="https://home.wah.su/" />
<meta name="twitter:title" content="WAH.su" /> <meta name="twitter:title" content="WAH.su" />
<meta name="twitter:description" content="A tech non-company with a whole lot of wah—100% tech, 200% wah!" /> <meta
<meta name="twitter:image" content="https://home.wah.su/static/og/opengraph.png" /> name="twitter:description"
content="A tech non-company with a whole lot of wah—100% tech, 200% wah!"
/>
<meta
name="twitter:image"
content="https://home.wah.su/static/og/opengraph.png"
/>
<meta property="og:title" content="WAH.su" /> <meta property="og:title" content="WAH.su" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://home.wah.su/" /> <meta property="og:url" content="https://home.wah.su/" />
<meta property="og:image" content="https://home.wah.su/static/og/opengraph.png" /> <meta
<meta property="og:description" content="A tech non-company with a whole lot of wah—100% tech, 200% wah!" /> property="og:image"
content="https://home.wah.su/static/og/opengraph.png"
/>
<meta
property="og:description"
content="A tech non-company with a whole lot of wah—100% tech, 200% wah!"
/>
</head> </head>
<body className="bg-[#1A0F05] container mx-auto max-w-[1210px] text-white py-8 overflow-x-hidden"> <body className="bg-[#1A0F05] container mx-auto max-w-[1210px] text-white overflow-hidden">
{children} <div className="background-grid w-full min-h-[140dvh] h-full absolute inset-0 overflow-hidden -z-50"></div>
<div id="cursor" className="overflow-hidden -z-50">
<div
className="background-grid w-[256px] h-[256px] rounded-full absolute overflow-hidden top-0 left-0 -z-50"
id="cursor-sec"
></div>
<div
className="w-0 h-0 absolute overflow-hidden top-0 left-0 -z-50"
id="cursor-prim"
></div>
</div>
<div className="overflow-y-auto max-h-[105%] pb-16 scrollbar-hidden">{children}</div>
<script src="/static/js/cursor.js"></script>
</body> </body>
</html> </html>
</> </>