init temp
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
package-lock.json
|
|
@ -0,0 +1,373 @@
|
||||||
|
*,
|
||||||
|
*::after,
|
||||||
|
*::before {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-size: 14px;
|
||||||
|
--color-text: #000;
|
||||||
|
--color-bg: #f2f1eb;
|
||||||
|
--color-link: #000;
|
||||||
|
--color-link-hover: #000;
|
||||||
|
--page-padding: 1rem;
|
||||||
|
--columns: 15;
|
||||||
|
--cursor-blend-mode: difference;
|
||||||
|
--cursor-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-1 {
|
||||||
|
--color-text: #cdbcbc;
|
||||||
|
--color-bg: #000;
|
||||||
|
--color-link: #fff;
|
||||||
|
--color-link-hover: #fff;
|
||||||
|
--cursor-bg: #5cafc1;
|
||||||
|
--cursor-blend-mode: exclusion;
|
||||||
|
--gradient-text-1: #e8c942;
|
||||||
|
--gradient-text-2: rgb(148 98 209);
|
||||||
|
background-image: url(../img/bg1.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-2 {
|
||||||
|
--cursor-bg: #47ea82;
|
||||||
|
--cursor-blend-mode: overlay;
|
||||||
|
--gradient-text-1: #85f2c3;
|
||||||
|
--gradient-text-2: rgb(246 99 115);
|
||||||
|
background-image: url(../img/bg2.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-3 {
|
||||||
|
--color-text: #234acd;
|
||||||
|
--color-bg: #000;
|
||||||
|
--color-link: #6fd74e;
|
||||||
|
--color-link-hover: #fff;
|
||||||
|
--cursor-bg: #db970b;
|
||||||
|
--cursor-blend-mode: overlay;
|
||||||
|
--gradient-text-1: #1728eb;
|
||||||
|
--gradient-text-2: rgb(95 238 56);
|
||||||
|
background-image: url(../img/bg3.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-4 {
|
||||||
|
--color-text: #fff;
|
||||||
|
--color-bg: #000;
|
||||||
|
--color-link: #9fdee9;
|
||||||
|
--color-link-hover: #fff;
|
||||||
|
--cursor-bg: #f3d006;
|
||||||
|
--cursor-blend-mode: exclusion;
|
||||||
|
--gradient-text-1: #aedfea;
|
||||||
|
--gradient-text-2: rgb(253 235 188);
|
||||||
|
background-image: url(../img/bg4.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-5 {
|
||||||
|
--cursor-bg: #ea5b2acc;
|
||||||
|
--gradient-text-1: #09314c;
|
||||||
|
--gradient-text-2: rgb(242 133 93);
|
||||||
|
--cursor-blend-mode: none;
|
||||||
|
background-image: url(../img/bg5.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-6 {
|
||||||
|
--cursor-bg: #c54733;
|
||||||
|
--gradient-text-1: #000;
|
||||||
|
--gradient-text-2: rgb(234 105 79);
|
||||||
|
--cursor-blend-mode: none;
|
||||||
|
background-image: url(../img/bg6.jpg);
|
||||||
|
--cursor-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-7 {
|
||||||
|
--cursor-bg: #901ee9;
|
||||||
|
--gradient-text-1: #000;
|
||||||
|
--gradient-text-2: rgb(94 85 147);
|
||||||
|
--cursor-radius: 50%;
|
||||||
|
--cursor-blend-mode: color-burn;
|
||||||
|
background-image: url(../img/bg7.jpg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-8 {
|
||||||
|
--cursor-bg: radial-gradient(#fddc6d 10%,transparent);
|
||||||
|
--gradient-text-1: #000;
|
||||||
|
--gradient-text-2: rgb(94 85 147);
|
||||||
|
background-image: url(../img/bg8.jpg);
|
||||||
|
--cursor-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
font-family: "source-code-pro", monospace;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Loader */
|
||||||
|
.js .loading::before,
|
||||||
|
.js .loading::after {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js .loading::before {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.js .loading::after {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
margin: -30px 0 0 -30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0.4;
|
||||||
|
background: var(--color-link);
|
||||||
|
animation: loaderAnim 0.7s linear infinite alternate forwards;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loaderAnim {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale3d(0.5,0.5,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--color-link);
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-link-hover);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */
|
||||||
|
a:focus {
|
||||||
|
/* Provide a fallback style for browsers
|
||||||
|
that don't support :focus-visible */
|
||||||
|
outline: none;
|
||||||
|
background: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus:not(:focus-visible) {
|
||||||
|
/* Remove the focus indicator on mouse-focus for browsers
|
||||||
|
that do support :focus-visible */
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus-visible {
|
||||||
|
/* Draw a very noticeable focus style for
|
||||||
|
keyboard-focus on browsers that do support
|
||||||
|
:focus-visible */
|
||||||
|
outline: 2px solid red;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unbutton {
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unbutton:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--page-padding);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
grid-template-areas: 'title' 'prev' 'sponsor' 'demos';
|
||||||
|
grid-gap: 0.5rem;
|
||||||
|
justify-items: start;
|
||||||
|
align-self: start;
|
||||||
|
justify-self: start;
|
||||||
|
pointer-events: none;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
body #cdawrap {
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame a {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__title {
|
||||||
|
grid-area: title;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__title-main {
|
||||||
|
font-size: inherit;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__title-back {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-bottom: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__title-back span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__title-back svg {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__prev {
|
||||||
|
grid-area: prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__demos {
|
||||||
|
grid-area: demos;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame__demos-item:first-child {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.frame__demos-item {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 var(--page-padding);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: start;
|
||||||
|
font-family: "greycliff-cf", sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h2 {
|
||||||
|
font-size: 16vw;
|
||||||
|
line-height: 1;
|
||||||
|
margin: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: var(--gradient-text-1);
|
||||||
|
background-image: linear-gradient(45deg, var(--gradient-text-1), var(--gradient-text-2));
|
||||||
|
background-size: 100%;
|
||||||
|
background-repeat: repeat;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
-moz-background-clip: text;
|
||||||
|
-moz-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h2 i {
|
||||||
|
font-family: "lores-9-plus-wide", sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
letter-spacing: -1.75vw;
|
||||||
|
font-size: 14.25vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
margin: 3vh 0 0 0;
|
||||||
|
max-width: 30ch;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: clamp(1.5rem, 2vw, 2rem);
|
||||||
|
font-variation-settings: "wght" 400, "opsz" 72, "ital" 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: relative; /* Относительное позиционирование для правильного расположения псевдоэлемента */
|
||||||
|
z-index: 1; /* Чтобы текст был поверх фона */
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -0.5em;
|
||||||
|
right: -0.5em;
|
||||||
|
bottom: 0;
|
||||||
|
background: var(--gradient-text-2); /* Используем ваш цвет для фона */
|
||||||
|
opacity: 0.8; /* Полупрозрачность */
|
||||||
|
border-radius: 8px; /* Плавные углы */
|
||||||
|
z-index: -1; /* Чтобы фон был под текстом */
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cyrillic {
|
||||||
|
font-family: "Moderustic", sans-serif; /* Укажите любой шрифт для кириллицы */
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor {
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 99;
|
||||||
|
mix-blend-mode: var(--cursor-blend-mode);
|
||||||
|
--size: calc(100vw / var(--columns));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor__inner {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(var(--columns), var(--size));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor__inner-box {
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background: var(--cursor-bg);
|
||||||
|
opacity: 0;
|
||||||
|
border-radius: var(--cursor-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 53em) {
|
||||||
|
:root {
|
||||||
|
--columns: 30;
|
||||||
|
--page-padding: 2rem;
|
||||||
|
}
|
||||||
|
.frame {
|
||||||
|
grid-template-columns: auto auto auto 1fr;
|
||||||
|
grid-template-areas: 'title prev sponsor demos';
|
||||||
|
justify-items: start;
|
||||||
|
grid-gap: 2rem;
|
||||||
|
}
|
||||||
|
.frame__demos {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
.frame__demos-item:first-child {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* The Typekit service used to deliver this font or fonts for use on websites
|
||||||
|
* is provided by Adobe and is subject to these Terms of Use
|
||||||
|
* http://www.adobe.com/products/eulas/tou_typekit. For font license
|
||||||
|
* information, see the list below.
|
||||||
|
*
|
||||||
|
* greycliff-cf:
|
||||||
|
* - http://typekit.com/eulas/00000000000000007735fa47
|
||||||
|
* - http://typekit.com/eulas/00000000000000007735fa4c
|
||||||
|
* lores-9-plus-wide:
|
||||||
|
* - http://typekit.com/eulas/00000000000000007735bf8c
|
||||||
|
* source-code-pro:
|
||||||
|
* - http://typekit.com/eulas/00000000000000007735dc00
|
||||||
|
* - http://typekit.com/eulas/00000000000000007735dc06
|
||||||
|
*
|
||||||
|
* © 2009-2024 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
/*{"last_published":"2023-06-06 22:06:27 UTC"}*/
|
||||||
|
|
||||||
|
/*@import url("https://p.typekit.net/p.css?s=1&k=ftj8drh&ht=tk&f=17453.17454.28337.49469.49474&a=1494256&app=typekit&e=css");*/
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "source-code-pro";
|
||||||
|
src: url("fonts/source-code-pro-woff2-300.font") format("woff2"),
|
||||||
|
url("fonts/source-code-pro-woff-300.font") format("woff"),
|
||||||
|
url("fonts/source-code-pro-opentype-300.font") format("opentype");
|
||||||
|
font-display: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-stretch: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "source-code-pro";
|
||||||
|
src: url("fonts/source-code-pro-woff2-400.font") format("woff2"),
|
||||||
|
url("fonts/source-code-pro-woff-400.font") format("woff"),
|
||||||
|
url("fonts/source-code-pro-opentype-400.font") format("opentype");
|
||||||
|
font-display: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-stretch: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "lores-9-plus-wide";
|
||||||
|
src: url("fonts/lores-9-plus-wide-woff2-400.font") format("woff2"),
|
||||||
|
url("fonts/lores-9-plus-wide-woff-400.font") format("woff"),
|
||||||
|
url("fonts/lores-9-plus-wide-opentype-400.font") format("opentype");
|
||||||
|
font-display: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-stretch: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "greycliff-cf";
|
||||||
|
src: url("fonts/greycliff-cf-woff2-700.font") format("woff2"),
|
||||||
|
url("fonts/greycliff-cf-woff-700.font") format("woff"),
|
||||||
|
url("fonts/greycliff-cf-opentype-700.font") format("opentype");
|
||||||
|
font-display: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-stretch: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "greycliff-cf";
|
||||||
|
src: url("fonts/greycliff-cf-woff2-300.font") format("woff2"),
|
||||||
|
url("fonts/greycliff-cf-woff-300.font") format("woff"),
|
||||||
|
url("fonts/greycliff-cf-opentype-300.font") format("opentype");
|
||||||
|
font-display: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-stretch: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Moderustic';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/moderustic/v1/2-c39J9s3o6eLFNHFdXYaOX1UUnf3GLnYjALsQNd7Zehaw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
.tk-source-code-pro { font-family: "source-code-pro",monospace; }
|
||||||
|
.tk-lores-9-plus-wide { font-family: "lores-9-plus-wide",sans-serif; }
|
||||||
|
.tk-greycliff-cf { font-family: "greycliff-cf",sans-serif; }
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 195 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 242 KiB |
|
@ -0,0 +1,63 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru" class="no-js">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>hubMC</title>
|
||||||
|
<meta name="description" content="hubMC server website" />
|
||||||
|
<meta name="keywords" content="hubmc, rumine, ru-mine, minecraft, create" />
|
||||||
|
<meta name="author" content="itqop" />
|
||||||
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
|
<link rel="stylesheet" href="css/ftj8drh.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/base.css" />
|
||||||
|
<script>document.documentElement.className="js";var supportsCssVars=function(){var e,t=document.createElement("style");return t.innerHTML="root: { --tmp-var: bold; }",document.head.appendChild(t),e=!!(window.CSS&&window.CSS.supports&&window.CSS.supports("font-weight","var(--tmp-var)")),t.parentNode.removeChild(t),e};supportsCssVars()||alert("Please view this demo in a modern browser that supports CSS Variables.");
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const randomClass = `demo-${Math.floor(Math.random() * 8) + 1}`;
|
||||||
|
document.body.className = randomClass;
|
||||||
|
const paragraph = document.getElementById("target-text");
|
||||||
|
paragraph.innerHTML = paragraph.innerHTML.replace(/([\u0400-\u04FF]+)/g, '<span class="cyrillic">$1</span>');
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="demo-1">
|
||||||
|
<main>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame__title">
|
||||||
|
<h1 class="frame__title-main">hubMC</h1>
|
||||||
|
<a aria-label="TEMP" class="frame__title-back" href="https://discord.gg/AyRRFG7e">
|
||||||
|
<span class="oh__inner">TEMP</span>
|
||||||
|
<svg width="18px" height="18px" viewBox="0 0 24 24"><path vector-effect="non-scaling-stroke" d="M18.25 15.5a.75.75 0 00.75-.75v-9a.75.75 0 00-.75-.75h-9a.75.75 0 000 1.5h7.19L6.22 16.72a.75.75 0 101.06 1.06L17.5 7.56v7.19c0 .414.336.75.75.75z"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<a class="frame__prev" href="https://discord.gg/AyRRFG7e">Дискорд</a>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<h2>H<i>ub</i>M<i>C</i></h2>
|
||||||
|
<p id="target-text">hubMC* - концептуально новый проект. (*WIP)<br>& rumine в сердечке</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</main>
|
||||||
|
<div class="cursor">
|
||||||
|
<div class="cursor__inner">
|
||||||
|
<!-- cursor__inner-box elements come here -->
|
||||||
|
</div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||||
|
<defs>
|
||||||
|
<filter id="gooey">
|
||||||
|
<feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="3.2" />
|
||||||
|
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -7" result="goo" />
|
||||||
|
<feComposite in="SourceGraphic" in2="goo" operator="atop" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="js/gsap.min.js"></script>
|
||||||
|
<script type="module" src="js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,143 @@
|
||||||
|
// Import required functions from './utils.js'
|
||||||
|
import { getMousePos, getWinSize, isFirefox } from './utils.js';
|
||||||
|
|
||||||
|
// Initialize mouse position object
|
||||||
|
let mousepos = {x: 0, y: 0};
|
||||||
|
|
||||||
|
// Update 'mousepos' with the current mouse position
|
||||||
|
const updateMousePos = ev => {
|
||||||
|
mousepos = getMousePos(ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen for 'mousemove' and 'pointermove' events and update 'mousepos' accordingly
|
||||||
|
window.addEventListener('mousemove', updateMousePos);
|
||||||
|
window.addEventListener('pointermove', updateMousePos, { passive: true });
|
||||||
|
|
||||||
|
// Initialize window size object
|
||||||
|
let winsize = getWinSize();
|
||||||
|
|
||||||
|
// Recalculate window size on 'resize' event
|
||||||
|
window.addEventListener('resize', ev => {
|
||||||
|
winsize = getWinSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Class representing the Goo cursor
|
||||||
|
export class GooCursor {
|
||||||
|
// Initialize DOM and style related properties
|
||||||
|
DOM = {
|
||||||
|
// Main DOM element
|
||||||
|
el: null,
|
||||||
|
// .cursor__inner element
|
||||||
|
inner: null,
|
||||||
|
// cells that get shown on mousemove
|
||||||
|
cells: null,
|
||||||
|
};
|
||||||
|
// Size of one cell (.cursor__inner-box)
|
||||||
|
cellSize;
|
||||||
|
// Number of cell rows
|
||||||
|
rows;
|
||||||
|
// Number of cell columns
|
||||||
|
columns;
|
||||||
|
// Settings
|
||||||
|
settings = {
|
||||||
|
// Time that one cells gets visible before fading out
|
||||||
|
ttl: 0.2
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(DOM_el) {
|
||||||
|
this.DOM.el = DOM_el;
|
||||||
|
|
||||||
|
// Cells wrapper element that gets the SVG filter applied
|
||||||
|
this.DOM.inner = this.DOM.el.querySelector('.cursor__inner');
|
||||||
|
|
||||||
|
// Too much for firefox...
|
||||||
|
if ( !isFirefox() ) {
|
||||||
|
this.DOM.inner.style.filter = 'url(#gooey)';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ttl from data attr
|
||||||
|
this.settings.ttl = this.DOM.el.getAttribute('data-ttl') || this.settings.ttl;
|
||||||
|
|
||||||
|
// Calculate how many cells to insert into the .cursor__inner element:
|
||||||
|
this.layout();
|
||||||
|
|
||||||
|
// Initialize/Bind some events
|
||||||
|
this.initEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize/bind events
|
||||||
|
*/
|
||||||
|
initEvents() {
|
||||||
|
// Recalculate and create the .cursor__inner-box elements on 'resize'
|
||||||
|
window.addEventListener('resize', () => this.layout());
|
||||||
|
|
||||||
|
// Show/hide cells on 'mousemove' or 'pointermove' events
|
||||||
|
const handleMove = () => {
|
||||||
|
// Check which cell is being "hovered"
|
||||||
|
const cell = this.getCellAtCursor();
|
||||||
|
|
||||||
|
if (cell === null || this.cachedCell === cell) return;
|
||||||
|
// Cache it
|
||||||
|
this.cachedCell = cell;
|
||||||
|
// Set opacity to 1
|
||||||
|
gsap.set(cell, { opacity: 1 });
|
||||||
|
// Set it back to 0 after a certain delay
|
||||||
|
gsap.set(cell, { opacity: 0, delay: this.settings.ttl });
|
||||||
|
// gsap.to(cell, { duration: 0.3, ease: 'expo', opacity: 0, delay: this.settings.ttl });
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', handleMove);
|
||||||
|
window.addEventListener('pointermove', handleMove, { passive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate and create the .cursor__inner-box elements.
|
||||||
|
* These are the elements that get shown when moving the mouse
|
||||||
|
*/
|
||||||
|
layout() {
|
||||||
|
// The number of columns is defined in a CSS variable --columns
|
||||||
|
this.columns = getComputedStyle(this.DOM.el).getPropertyValue('--columns');
|
||||||
|
// Calculate cell size
|
||||||
|
this.cellSize = winsize.width/this.columns;
|
||||||
|
// Calculate number of rows
|
||||||
|
this.rows = Math.ceil(winsize.height/this.cellSize);
|
||||||
|
// Calculate the total amount of cells (rows x columns)
|
||||||
|
this.cellsTotal = this.rows * this.columns;
|
||||||
|
// Insert [this.cellsTotal] cursor__inner-box elements inside the .cursor__inner element
|
||||||
|
let innerStr = '';
|
||||||
|
// Erase contents
|
||||||
|
this.DOM.inner.innerHTML = '';
|
||||||
|
|
||||||
|
const customColorsAttr = this.DOM.el.getAttribute('data-custom-colors');
|
||||||
|
let customColorsArr;
|
||||||
|
let customColorsTotal = 0;
|
||||||
|
if ( customColorsAttr ) {
|
||||||
|
customColorsArr = this.DOM.el.getAttribute('data-custom-colors').split(',');
|
||||||
|
customColorsTotal = customColorsArr ? customColorsArr.length : 0;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.cellsTotal; ++i) {
|
||||||
|
innerStr += customColorsTotal === 0 ?
|
||||||
|
'<div class="cursor__inner-box"></div>' :
|
||||||
|
`<div style="transform: scale(${gsap.utils.random(0.5,2)}); background:${customColorsArr[Math.round(gsap.utils.random(0,customColorsTotal-1))]}" class="cursor__inner-box"></div>`;
|
||||||
|
}
|
||||||
|
this.DOM.inner.innerHTML = innerStr;
|
||||||
|
this.DOM.cells = this.DOM.inner.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cell at the position of the cursor
|
||||||
|
*/
|
||||||
|
getCellAtCursor() {
|
||||||
|
const columnIndex = Math.floor(mousepos.x / this.cellSize);
|
||||||
|
const rowIndex = Math.floor(mousepos.y / this.cellSize);
|
||||||
|
const cellIndex = rowIndex * this.columns + columnIndex;
|
||||||
|
|
||||||
|
if ( cellIndex >= this.cellsTotal || cellIndex < 0 ) {
|
||||||
|
console.error('Cell index out of bounds');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.DOM.cells[cellIndex];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { GooCursor } from './cursor.js';
|
||||||
|
|
||||||
|
const cursorEl = document.querySelector('.cursor');
|
||||||
|
|
||||||
|
// Initialize cursor
|
||||||
|
const goo = new GooCursor(cursorEl);
|
||||||
|
|
||||||
|
// Easter egg: click anywhere
|
||||||
|
|
||||||
|
window.addEventListener('click', () => {
|
||||||
|
gsap.
|
||||||
|
timeline()
|
||||||
|
.addLabel('start', 0)
|
||||||
|
.to(goo.DOM.cells, {
|
||||||
|
duration: 1,
|
||||||
|
ease: 'power4',
|
||||||
|
opacity: 1,
|
||||||
|
stagger: {
|
||||||
|
from: [...goo.DOM.cells].indexOf(goo.getCellAtCursor()),
|
||||||
|
each: 0.02,
|
||||||
|
grid: [goo.rows,goo.columns]
|
||||||
|
}
|
||||||
|
}, 'start')
|
||||||
|
.to(goo.DOM.cells, {
|
||||||
|
duration: 1,
|
||||||
|
ease: 'power1',
|
||||||
|
opacity: 0,
|
||||||
|
stagger: {
|
||||||
|
from: [...goo.DOM.cells].indexOf(goo.getCellAtCursor()),
|
||||||
|
each: 0.03,
|
||||||
|
grid: [goo.rows,goo.columns]
|
||||||
|
}
|
||||||
|
}, 'start+=0.3')
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Returns the mouse position
|
||||||
|
const getMousePos = e => {
|
||||||
|
return {
|
||||||
|
x : e.clientX,
|
||||||
|
y : e.clientY
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the window width and height
|
||||||
|
const getWinSize = () => {
|
||||||
|
return {
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFirefox = () => navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
|
|
||||||
|
export {
|
||||||
|
getMousePos,
|
||||||
|
getWinSize,
|
||||||
|
isFirefox,
|
||||||
|
};
|