Compare commits

...

14 Commits

Author SHA1 Message Date
57e731a7b9 perf: optimize multipleSplats perfomance
Reduces buffer swaps from O(2N) to O(2), N = number of splats

Minimizes expensive WebGL context state changes

Processes all velocity updates first to keep similar operations contiguous then handles all dye updates for better texture cache utilization
2025-01-29 05:54:58 +03:00
dc3462a864 refactor: restructure 2025-01-29 04:55:18 +03:00
4a6aa94e39 refactor: add jsdoc, improve code redability 2025-01-28 19:50:28 +03:00
618fc16ed8 add docker 2023-06-13 21:26:11 +03:00
5e6bdacdbb update deps 2023-06-13 21:18:31 +03:00
b5e8457ea5 Bring back spotify button and insta link 2023-01-05 14:40:11 +03:00
1bcc01bfe8 migrate to npm and update dependencies 2023-01-05 14:38:42 +03:00
e14b793fbc update readme 2022-08-23 15:59:21 +03:00
1c93c61309 add co-author to fluid.js MIT License 2022-06-24 17:09:45 +03:00
0fe859947b some changes
* change links according to gitlab in readme file
* change git url
2022-06-24 17:00:59 +03:00
0eae708b22 add analytics 2022-05-19 10:24:53 +03:00
b1acaee645 migrate to self hosted git 2022-05-05 11:41:25 +03:00
6aecc455dd Update README.md
change git protocol
2022-04-16 01:25:49 +03:00
7b84c799b4 temporary removed link to vizualizer due the maintenance 2022-04-15 19:38:03 +03:00
21 changed files with 1968 additions and 1090 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

View File

@ -2,7 +2,9 @@
See: [zeldon.ru](https://zeldon.ru).
My personal website. An [MIT](https://github.com/xzeldon/zeldon-site/blob/main/LICENSE) licensed, easy modifiable.
My personal website. An [MIT](https://git.zeldon.ru/zeldon/zeldon-site/src/branch/main/LICENSE) licensed, easy modifiable.
Mirror on my [<img src="https://git.zeldon.ru/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.zeldon.ru/zeldon/zeldon-site)
## Dependencies
@ -13,7 +15,7 @@ Only [Vite](https://vitejs.dev/) for development and bundling.
To download the repository and install dependencies, run the following commands:
```bash
git clone git://github.com/xzeldon/zeldon-site.git # replace [xzeldon] with your github username if you fork first.
git clone https://git.zeldon.ru/zeldon/zeldon-site.git
cd zeldon-site
npm install
```
@ -31,6 +33,7 @@ Your web browser should automatically open to `<ip>:<port>:<path>` default: [htt
## Static export
To statically export the site, run this command:
```bash
npm run build
```

14
config/Dockerfile Normal file
View File

@ -0,0 +1,14 @@
FROM node:24-slim as build
WORKDIR /opt
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.24-alpine-slim
COPY config/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /opt/dist /usr/share/nginx/html

14
config/docker-compose.yml Normal file
View File

@ -0,0 +1,14 @@
version: "3"
services:
zeldon-site:
image: zeldon-site:latest
container_name: zeldon-site
build:
context: .
dockerfile: config/Dockerfile
ports:
- "3123:80"
restart: unless-stopped
volumes:
- ./config/nginx.conf:/etc/nginx/conf.d/default.conf:ro

10
config/nginx.conf Normal file
View File

@ -0,0 +1,10 @@
server {
listen 80;
# path to files for serve
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /index.html;
}
}

View File

@ -1,47 +1,58 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="Cache-Control" content="no-cache" />
<head>
<meta charset="utf-8">
<meta http-equiv="Cache-Control" content="no-cache">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<link rel="icon" href="favicon/favicon.ico" sizes="any">
<link rel="icon" href="favicon/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="favicon/apple-touch-icon.png">
<link rel="icon" href="favicon/favicon.ico" sizes="any" />
<link rel="icon" href="favicon/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="favicon/apple-touch-icon.png" />
<title>zeldØƞ</title>
<meta name="description" content="zeldon's website">
<meta name="description" content="zeldon's website" />
<meta property="og:type" content="website">
<meta property="og:title" content="zeldØƞ">
<meta property="og:description" content="zeldon's website">
<meta property="og:url" content="https://zeldon.ru">
<meta property="og:image" content="ogimage.jpg">
<meta property="og:type" content="website" />
<meta property="og:title" content="zeldØƞ" />
<meta property="og:description" content="zeldon's website" />
<meta property="og:url" content="https://zeldon.ru" />
<meta property="og:image" content="ogimage.jpg" />
</head>
<!-- analytics -->
<script async defer data-domain="zeldon.ru" src="https://analytics.zeldon.ru/js/plausible.js"></script>
</head>
<body>
<body>
<div class="container">
<div class="content">
<div class="content-info">
<h1 class="name perspective">TIMOFEY <br>GELAZONIYA</h1>
<h1 class="name perspective">TIMOFEY <br />GELAZONIYA</h1>
<h4 class="greeting perspective"></h4>
<h4 class="clock perspective"></h4>
</div>
<div class="button-container perspective">
<button class="button button--hyperion" onclick="window.open('https://spotify.zeldon.ru', '_blank')"
type="button">
<button
class="button button--hyperion"
onclick="window.open('https://spotify.zeldon.ru', '_blank')"
type="button"
>
<span class="button-inner">
<svg class="spotify-icon" height="30" width="30" viewBox="0 0 170 170">
<svg
class="spotify-icon"
height="30"
width="30"
viewBox="0 0 170 170"
>
<path
d="m83.996 0.277c-46.249 0-83.743 37.493-83.743 83.742 0 46.251 37.494 83.741 83.743 83.741 46.254 0 83.744-37.49 83.744-83.741 0-46.246-37.49-83.738-83.745-83.738l0.001-0.004zm38.404 120.78c-1.5 2.46-4.72 3.24-7.18 1.73-19.662-12.01-44.414-14.73-73.564-8.07-2.809 0.64-5.609-1.12-6.249-3.93-0.643-2.81 1.11-5.61 3.926-6.25 31.9-7.291 59.263-4.15 81.337 9.34 2.46 1.51 3.24 4.72 1.73 7.18zm10.25-22.805c-1.89 3.075-5.91 4.045-8.98 2.155-22.51-13.839-56.823-17.846-83.448-9.764-3.453 1.043-7.1-0.903-8.148-4.35-1.04-3.453 0.907-7.093 4.354-8.143 30.413-9.228 68.222-4.758 94.072 11.127 3.07 1.89 4.04 5.91 2.15 8.976v-0.001zm0.88-23.744c-26.99-16.031-71.52-17.505-97.289-9.684-4.138 1.255-8.514-1.081-9.768-5.219-1.254-4.14 1.08-8.513 5.221-9.771 29.581-8.98 78.756-7.245 109.83 11.202 3.73 2.209 4.95 7.016 2.74 10.733-2.2 3.722-7.02 4.949-10.73 2.739z" />
d="m83.996 0.277c-46.249 0-83.743 37.493-83.743 83.742 0 46.251 37.494 83.741 83.743 83.741 46.254 0 83.744-37.49 83.744-83.741 0-46.246-37.49-83.738-83.745-83.738l0.001-0.004zm38.404 120.78c-1.5 2.46-4.72 3.24-7.18 1.73-19.662-12.01-44.414-14.73-73.564-8.07-2.809 0.64-5.609-1.12-6.249-3.93-0.643-2.81 1.11-5.61 3.926-6.25 31.9-7.291 59.263-4.15 81.337 9.34 2.46 1.51 3.24 4.72 1.73 7.18zm10.25-22.805c-1.89 3.075-5.91 4.045-8.98 2.155-22.51-13.839-56.823-17.846-83.448-9.764-3.453 1.043-7.1-0.903-8.148-4.35-1.04-3.453 0.907-7.093 4.354-8.143 30.413-9.228 68.222-4.758 94.072 11.127 3.07 1.89 4.04 5.91 2.15 8.976v-0.001zm0.88-23.744c-26.99-16.031-71.52-17.505-97.289-9.684-4.138 1.255-8.514-1.081-9.768-5.219-1.254-4.14 1.08-8.513 5.221-9.771 29.581-8.98 78.756-7.245 109.83 11.202 3.73 2.209 4.95 7.016 2.74 10.733-2.2 3.722-7.02 4.949-10.73 2.739z"
/>
</svg>
<span>
<span>Sign in with Spotify</span>
@ -49,32 +60,43 @@
</span>
</button>
<div class="links-container">
<a class="link" target="_blank" rel="noopener noreferrer" href="https://vk.com/xzeldon">
<span class="link-text">
vk
</span>
<a
class="link"
target="_blank"
rel="noopener noreferrer"
href="https://vk.com/xzeldon"
>
<span class="link-text"> vk </span>
</a>
<a class="link" target="_blank" rel="noopener noreferrer" href="https://github.com/xzeldon">
<span class="link-text">
github
</span>
<a
class="link"
target="_blank"
rel="noopener noreferrer"
href="https://github.com/xzeldon"
>
<span class="link-text"> git </span>
</a>
<a class="link" target="_blank" rel="noopener noreferrer" href="https://t.me/xzeldon">
<span class="link-text">
telegram
</span>
<a
class="link"
target="_blank"
rel="noopener noreferrer"
href="https://git.zeldon.ru"
>
<span class="link-text"> gitea </span>
</a>
<a
class="link"
target="_blank"
rel="noopener noreferrer"
href="https://t.me/xzeldon"
>
<span class="link-text"> telegram </span>
</a>
<!-- <a class="link" target="_blank" rel="noopener noreferrer" href="https://www.instagram.com/zeeeldon">
<span class="link-text">
instagram
</span>
</a> -->
</div>
</div>
</div>
</div>
<canvas></canvas>
<script type="module" src="./src/main.js"></script>
</body>
</body>
</html>

544
package-lock.json generated Normal file
View File

@ -0,0 +1,544 @@
{
"name": "zeldon-site",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "zeldon-site",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"vite": "^4.3.9"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.17.19",
"@esbuild/android-arm64": "0.17.19",
"@esbuild/android-x64": "0.17.19",
"@esbuild/darwin-arm64": "0.17.19",
"@esbuild/darwin-x64": "0.17.19",
"@esbuild/freebsd-arm64": "0.17.19",
"@esbuild/freebsd-x64": "0.17.19",
"@esbuild/linux-arm": "0.17.19",
"@esbuild/linux-arm64": "0.17.19",
"@esbuild/linux-ia32": "0.17.19",
"@esbuild/linux-loong64": "0.17.19",
"@esbuild/linux-mips64el": "0.17.19",
"@esbuild/linux-ppc64": "0.17.19",
"@esbuild/linux-riscv64": "0.17.19",
"@esbuild/linux-s390x": "0.17.19",
"@esbuild/linux-x64": "0.17.19",
"@esbuild/netbsd-x64": "0.17.19",
"@esbuild/openbsd-x64": "0.17.19",
"@esbuild/sunos-x64": "0.17.19",
"@esbuild/win32-arm64": "0.17.19",
"@esbuild/win32-ia32": "0.17.19",
"@esbuild/win32-x64": "0.17.19"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"node_modules/postcss": {
"version": "8.4.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "3.25.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz",
"integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
"dev": true,
"dependencies": {
"esbuild": "^0.17.5",
"postcss": "^8.4.23",
"rollup": "^3.21.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
}
}
}

View File

@ -27,6 +27,6 @@
"serve": "vite preview"
},
"devDependencies": {
"vite": "^2.3.7"
"vite": "^4.3.9"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
import { event_listener_array, calc_delta_time } from './utils';
export function perspective_3d(class_name) {
const elements = document.body.getElementsByClassName(class_name);
let velocity_x = 0;
let velocity_y = 0;
let rotation_x = 0;
let rotation_y = 0;
let target_rotation_x = 0;
let target_rotation_y = 0;
(function update() {
let dt = calc_delta_time();
const ss = .08;
velocity_x = spring(rotation_x, target_rotation_x, velocity_x, 10, dt);
velocity_y = spring(rotation_y, target_rotation_y, velocity_y, 10, dt);
rotation_x += velocity_x * dt * ss;
rotation_y += velocity_y * dt * ss;
const style = `perspective(700px) rotateX(${rotation_y}rad) rotateY(${rotation_x}rad)`;
for (const el of elements) {
el.style.transform = style;
}
requestAnimationFrame(update);
})();
event_listener_array(window, ["mousemove", "touchmove"], (e) => {
if (e.changedTouches && e.changedTouches[0]) {
e = e.changedTouches[0];
}
target_rotation_x = (e.clientX / window.innerWidth) * 2 - 1;
target_rotation_y = -(e.clientY / window.innerHeight) * 2 + 1;
target_rotation_x = clamp(target_rotation_x, -0.5, 0.5);
target_rotation_y = clamp(target_rotation_y, -0.5, 0.5);
}, false);
function spring(position, target, velocity, omega, dt) {
let n1 = velocity - (position - target) * (Math.pow(omega, 2) * dt);
let n2 = 1 + omega * dt;
return n1 / Math.pow(n2, 2);
}
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
}
(function pick_greeting() {
const hours = new Date().getHours();
const greeing_el = document.querySelector(".greeting");
if (hours < 6) {
const data = "Good night";
greeing_el.textContent = data;
greeing_el.innerText = data;
} else if (hours >= 6 && hours < 12) {
const data = "Good morning";
greeing_el.textContent = data;
greeing_el.innerText = data;
} else if (hours >= 12 && hours < 16) {
const data = "Good afternoon";
greeing_el.textContent = data;
greeing_el.innerText = data;
} else if (hours >= 16 && hours <= 23) {
const data = "Good evening";
greeing_el.textContent = data;
greeing_el.innerText = data;
} else {
const data = "Hello";
greeing_el.textContent = data;
greeing_el.innerText = data;
}
setTimeout(pick_greeting, 6e4);
})();
(function render_time() {
const time = new Date();
let h = time.getHours();
h = h.toString().padStart(2, 0);
let m = time.getMinutes().toString().padStart(2, 0);
let s = time.getSeconds().toString().padStart(2, 0);
const clock_el = document.querySelector('.clock');
if (!clock_el) return;
const formatted_date = `${h}:${m}:${s}`;
clock_el.textContent = formatted_date;
clock_el.innerText = formatted_date;
setTimeout(render_time, 1e3);
})();

View File

@ -1,9 +0,0 @@
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1.0;
}
}

View File

@ -1,19 +0,0 @@
@font-face {
font-family: "Inter Var";
font-weight: 400 900;
font-display: swap;
font-style: normal;
src: url("/src/font/Inter.woff2") format("woff2");
}
html {
font-family: "Inter Var", sans-serif;
font-size: 17px;
box-sizing: border-box;
}
.greeting {
font-variation-settings: "wght" 400;
letter-spacing: 0rem;
line-height: 1.7rem;
}

135
src/effects.js vendored Normal file
View File

@ -0,0 +1,135 @@
import { addEventListeners, calcDeltaTime } from "./utils";
/**
* Adds 3D perspective rotation effect to elements with the specified class name.
* The rotation is controlled by mouse/touch movement and uses spring physics for smooth animation.
* @param {string} className - The class name of elements to apply the 3D effect to
*/
export const add3DRotationEffect = (className) => {
const elements = document.body.getElementsByClassName(className);
const state = {
velocity: { x: 0, y: 0 },
rotation: { x: 0, y: 0 },
targetRotation: { x: 0, y: 0 },
};
/**
* Calculates spring physics for smooth animation
* @param {number} position - Current position
* @param {number} target - Target position
* @param {number} velocity - Current velocity
* @param {number} omega - Angular frequency
* @param {number} dt - Delta time
* @returns {number} New velocity
*/
const spring = (position, target, velocity, omega, dt) => {
const n1 = velocity - (position - target) * (omega ** 2 * dt);
const n2 = 1 + omega * dt;
return n1 / n2 ** 2;
};
/**
* Clamps a value between min and max
* @param {number} value - Value to clamp
* @param {number} min - Minimum value
* @param {number} max - Maximum value
* @returns {number} Clamped value
*/
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
/**
* Updates rotation values and applies transform styles in animation frame
*/
const updateRotation = () => {
const dt = calcDeltaTime();
const springConstant = 0.08;
state.velocity.x = spring(
state.rotation.x,
state.targetRotation.x,
state.velocity.x,
10,
dt
);
state.velocity.y = spring(
state.rotation.y,
state.targetRotation.y,
state.velocity.y,
10,
dt
);
state.rotation.x += state.velocity.x * dt * springConstant;
state.rotation.y += state.velocity.y * dt * springConstant;
const style = `perspective(700px) rotateX(${state.rotation.y}rad) rotateY(${state.rotation.x}rad)`;
Array.from(elements).forEach((el) => (el.style.transform = style));
requestAnimationFrame(updateRotation);
};
/**
* Handles mouse/touch movement to update target rotation
* @param {(MouseEvent|TouchEvent)} e - Mouse or touch event
*/
const handleMovement = (e) => {
const event = e.changedTouches?.[0] || e;
state.targetRotation.x = (event.clientX / window.innerWidth) * 2 - 1;
state.targetRotation.y = -(event.clientY / window.innerHeight) * 2 + 1;
state.targetRotation.x = clamp(state.targetRotation.x, -0.5, 0.5);
state.targetRotation.y = clamp(state.targetRotation.y, -0.5, 0.5);
};
addEventListeners(window, ["mousemove", "touchmove"], handleMovement, false);
updateRotation();
};
/**
* Updates greeting text based on time of day.
* Updates every minute.
*/
export const updateGreeting = () => {
const hours = new Date().getHours();
const greetingEl = document.querySelector(".greeting");
if (!greetingEl) return;
/**
* Gets appropriate greeting based on hour of day
* @param {number} hours - Hour in 24-hour format
* @returns {string} Greeting text
*/
const getGreeting = (hours) => {
if (hours < 6) return "Good night";
if (hours < 12) return "Good morning";
if (hours < 16) return "Good afternoon";
if (hours <= 23) return "Good evening";
return "Hello";
};
const greeting = getGreeting(hours);
greetingEl.textContent = greeting;
setTimeout(updateGreeting, 60_000); // 60 seconds
};
/**
* Updates clock display with current time in HH:MM:SS format.
* Updates every second.
*/
export const updateTime = () => {
const clockEl = document.querySelector(".clock");
if (!clockEl) return;
const time = new Date();
const formatted_date = [time.getHours(), time.getMinutes(), time.getSeconds()]
.map((num) => num.toString().padStart(2, "0"))
.join(":");
clockEl.textContent = formatted_date;
setTimeout(updateTime, 1000);
};

View File

@ -1,18 +1,17 @@
// CSS Import
import './css/style.css';
import './css/font.css';
import './css/animation.css';
import './css/button.css';
import "./styles/base.css";
import "./styles/typography.css";
import "./styles/animations.css";
import "./styles/components.css";
// JS Import
import './app';
import "./effects";
import { add3DRotationEffect, updateGreeting, updateTime } from "./effects";
import { importJsAsModule } from "./utils";
import { perspective_3d } from './app';
import { import_js_as_module } from './utils';
const initialize = async () => {
await importJsAsModule("/fluid.js");
add3DRotationEffect("perspective");
updateGreeting();
updateTime();
};
window.onload = start;
async function start() {
await import_js_as_module('/fluid.js');
perspective_3d('perspective');
}
window.addEventListener("load", initialize);

View File

@ -0,0 +1,9 @@
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

19
src/styles/typography.css Normal file
View File

@ -0,0 +1,19 @@
@font-face {
font-family: "Inter Var";
font-weight: 400 900;
font-display: swap;
font-style: normal;
src: url("/src/assets/Inter.woff2") format("woff2");
}
html {
font-family: "Inter Var", sans-serif;
font-size: 17px;
box-sizing: border-box;
}
.greeting {
font-variation-settings: "wght" 400;
letter-spacing: 0rem;
line-height: 1.7rem;
}

View File

@ -1,31 +1,57 @@
/** Timestamp of the last update used for delta time calculation */
export let last_update = Date.now();
export function calc_delta_time() {
let now = Date.now();
let dt = (now - last_update) / 1e3;
dt = Math.min(dt, 0.016);
/**
* Calculates the time elapsed since the last update, capped at 60fps
* @returns {number} Delta time in seconds
*/
export function calcDeltaTime() {
const now = Date.now();
const MAX_DELTA = 0.016; // 60fps cap
let dt = (now - last_update) / 1000;
dt = Math.min(dt, MAX_DELTA);
last_update = now;
return dt;
}
export function event_listener_array(whos, event_names, callback, options = null) {
if (!Array.isArray(whos)) {
whos = [whos];
}
for (const name of event_names) {
for (const who of whos) {
who.addEventListener(name, callback, options);
}
}
}
/**
* Adds event listeners to one or more elements for multiple event types
* @param {HTMLElement|HTMLElement[]} elements - Single element or array of elements
* @param {string[]} eventNames - Array of event names to listen for
* @param {Function} callback - Event handler function
* @param {(boolean|AddEventListenerOptions|null)} [options=null] - Event listener options
*/
export function addEventListeners(
elements,
eventNames,
callback,
options = null
) {
// Convert single element to array if needed
const elementArray = Array.isArray(elements) ? elements : [elements];
export async function import_js_as_module(url) {
return new Promise((resole, reject) => {
const body = document.getElementsByTagName('body')[0];
const script = document.createElement('script');
script.type = 'module';
script.src = url;
script.onload = resole;
body.appendChild(script);
// Add event listeners to each element for each event name
eventNames.forEach((eventName) => {
elementArray.forEach((element) => {
element.addEventListener(eventName, callback, options);
});
});
}
/**
* Imports a JavaScript file as an ES module by injecting a script tag
* @param {string} url - URL of the JavaScript file to import
* @returns {Promise<void>} Resolves when the script has loaded
*/
export const importJsAsModule = async (url) => {
return new Promise((resolve, reject) => {
const body = document.querySelector("body");
const script = document.createElement("script");
script.type = "module";
script.src = url;
script.onload = resolve;
body.appendChild(script);
});
};

View File

@ -1,88 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
esbuild@^0.12.8:
version "0.12.9"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.9.tgz#bed4e7087c286cd81d975631f77d47feb1660070"
integrity sha512-MWRhAbMOJ9RJygCrt778rz/qNYgA4ZVj6aXnNPxFjs7PmIpb0fuB9Gmg5uWrr6n++XKwwm/RmSz6RR5JL2Ocsw==
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
is-core-module@^2.2.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
dependencies:
has "^1.0.3"
nanoid@^3.1.23:
version "3.1.23"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
path-parse@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
postcss@^8.3.4:
version "8.3.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
source-map-js "^0.6.2"
resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
rollup@^2.38.5:
version "2.52.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.52.2.tgz#a7e90d10ddae3e8472c2857bd9f44b09ef34a47a"
integrity sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==
optionalDependencies:
fsevents "~2.3.2"
source-map-js@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
vite@^2.3.7:
version "2.3.8"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.3.8.tgz#42e3e03953859fd410e4e6ab3d1cca0aab2adc3c"
integrity sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==
dependencies:
esbuild "^0.12.8"
postcss "^8.3.4"
resolve "^1.20.0"
rollup "^2.38.5"
optionalDependencies:
fsevents "~2.3.2"