forked from vyla-entertainment/home-frontend
219 lines
7.0 KiB
HTML
219 lines
7.0 KiB
HTML
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Vyla</title>
|
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
<link rel="apple-touch-icon" href="favicon.ico" />
|
|
<link rel="manifest" href="/manifest.webmanifest">
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin />
|
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Fira+Code:wght@300;400;500;600;700&display=swap"
|
|
rel="stylesheet" />
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<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">
|
|
|
|
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
|
|
|
<style>
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
background: black;
|
|
height: 100%;
|
|
}
|
|
|
|
canvas {
|
|
display: block;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
|
|
body::after {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 20;
|
|
background: radial-gradient(circle at center,
|
|
rgba(0, 0, 0, 0) 40%,
|
|
rgba(0, 0, 0, 1) 100%);
|
|
}
|
|
|
|
.center-text {
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 5rem;
|
|
font-weight: 700;
|
|
color: white;
|
|
pointer-events: none;
|
|
user-select: none;
|
|
z-index: 10;
|
|
max-height: 70vh;
|
|
min-width: 70vw;
|
|
text-align: center;
|
|
}
|
|
|
|
.footer {
|
|
position: fixed;
|
|
bottom: 20px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
display: flex;
|
|
gap: 30px;
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 1.1rem;
|
|
z-index: 1000;
|
|
text-align: center;
|
|
align-items: center;
|
|
white-space: nowrap;
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
.footer::before {
|
|
display: none !important;
|
|
}
|
|
|
|
.footer a {
|
|
color: rgb(182, 182, 182);
|
|
text-decoration: none;
|
|
transition: 0.2s ease;
|
|
}
|
|
|
|
.footer a:hover {
|
|
color: white;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.center-text {
|
|
font-size: 3rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<canvas id="c"></canvas>
|
|
|
|
<div class="center-text">
|
|
Vyla is no longer available as a hosted website. Use Vyla Home to access Vyla on desktop.
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<a href="https://gitlab.com/vyla-entertainment/home/-/releases" target="_blank"
|
|
rel="noopener noreferrer">Download Vyla Home</a>
|
|
<a href="https://docs.vyla.cc" target="_blank" rel="noopener noreferrer">Docs</a>
|
|
<a href="https://vyla.cc/discord" target="_blank" rel="noopener noreferrer">Discord</a>
|
|
</div>
|
|
|
|
<script>
|
|
const CHARS = ' .:-=+*#%@';
|
|
const FONT_SIZE = 50;
|
|
|
|
const canvas = document.getElementById('c');
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
let CW, CH;
|
|
let cols, rows;
|
|
let t = 0;
|
|
|
|
let mouseX = -9999;
|
|
let mouseY = -9999;
|
|
let lastMouseMove = 0;
|
|
let mouseStrength = 0;
|
|
|
|
const FADE_TIME = 250;
|
|
const SMOOTHING = 0.08;
|
|
|
|
function initFont() {
|
|
ctx.font = `${FONT_SIZE}px monospace`;
|
|
CW = Math.ceil(ctx.measureText('M').width);
|
|
CH = FONT_SIZE + 2;
|
|
ctx.textBaseline = 'top';
|
|
}
|
|
|
|
function resize() {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
initFont();
|
|
cols = Math.ceil(canvas.width / CW) + 1;
|
|
rows = Math.ceil(canvas.height / CH) + 1;
|
|
}
|
|
|
|
window.addEventListener('resize', resize);
|
|
|
|
window.addEventListener('mousemove', (e) => {
|
|
const rect = canvas.getBoundingClientRect();
|
|
mouseX = e.clientX - rect.left;
|
|
mouseY = e.clientY - rect.top;
|
|
lastMouseMove = performance.now();
|
|
});
|
|
|
|
function plasma(cx, cy, t) {
|
|
const x = cx + Math.sin(cy * 3 + t * 0.7) * 0.07;
|
|
const y = cy + Math.cos(cx * 3 + t * 0.5) * 0.07;
|
|
|
|
let v =
|
|
Math.sin(x * 10 + t) +
|
|
Math.sin(y * 10 + t) +
|
|
Math.sin((x + y) * 7 + t) +
|
|
Math.sin(Math.sqrt(x * x + y * y) * 12 - t * 1.2) +
|
|
Math.sin(x * 6 - t * 0.8) +
|
|
Math.sin(y * 8 + t * 0.9);
|
|
|
|
return (v / 6 + 1) / 2;
|
|
}
|
|
|
|
function render() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
t += 0.03;
|
|
|
|
const elapsed = performance.now() - lastMouseMove;
|
|
const targetStrength = Math.max(0, 1 - elapsed / FADE_TIME);
|
|
|
|
mouseStrength += (targetStrength - mouseStrength) * SMOOTHING;
|
|
|
|
for (let row = 0; row < rows; row++) {
|
|
for (let col = 0; col < cols; col++) {
|
|
const x = col * CW;
|
|
const y = row * CH;
|
|
|
|
const dx = x - mouseX;
|
|
const dy = y - mouseY;
|
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
const force = (7000 / (dist * dist + 1500)) * mouseStrength;
|
|
|
|
const offsetX = dx * force;
|
|
const offsetY = dy * force;
|
|
|
|
const v = plasma(col / cols, row / rows, t);
|
|
const brightness = Math.round(v * 255);
|
|
const charIdx = Math.floor(v * (CHARS.length - 0.001));
|
|
const ch = CHARS[charIdx];
|
|
|
|
ctx.fillStyle = `rgb(${brightness},${brightness},${brightness})`;
|
|
ctx.fillText(ch, x + offsetX, y + offsetY);
|
|
}
|
|
}
|
|
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
resize();
|
|
render();
|
|
</script>
|
|
</body> |