init elas atelier #1
@@ -5,8 +5,7 @@
|
|||||||
* Renders an aria-hidden overlay root on every page. All visuals are CSS,
|
* Renders an aria-hidden overlay root on every page. All visuals are CSS,
|
||||||
* scoped to `.cybersigil .cs-fx*` in global.css, so this is an inert,
|
* scoped to `.cybersigil .cs-fx*` in global.css, so this is an inert,
|
||||||
* display:none no-op under every other theme. The bundled script only wires
|
* display:none no-op under every other theme. The bundled script only wires
|
||||||
* the JS-driven mechanics (custom sigil cursor + fading trail, scroll-entry
|
* the scroll-entry databend on images and self-disables off-theme or under
|
||||||
* databend on images) and self-disables off-theme, on touch, or under
|
|
||||||
* prefers-reduced-motion.
|
* prefers-reduced-motion.
|
||||||
*/
|
*/
|
||||||
---
|
---
|
||||||
@@ -21,70 +20,12 @@
|
|||||||
<i class="cs-fx-corner cs-fx-corner--br"></i>
|
<i class="cs-fx-corner cs-fx-corner--br"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cursor lives in its own top-level, un-contained, max-z root so it floats
|
|
||||||
above every modal/library (Search + AssetManager are z-[200]). -->
|
|
||||||
<div class="cs-cursor-root" aria-hidden="true">
|
|
||||||
<div class="cs-cursor">
|
|
||||||
<span class="cs-cursor-ring"></span>
|
|
||||||
<span class="cs-cursor-core"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function initCyberFx() {
|
function initCyberFx() {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
if (!root.classList.contains('cybersigil')) return;
|
if (!root.classList.contains('cybersigil')) return;
|
||||||
|
|
||||||
const fx = document.querySelector('.cs-fx') as HTMLElement | null;
|
|
||||||
const cursorRoot = document.querySelector('.cs-cursor-root') as HTMLElement | null;
|
|
||||||
if (!fx || !cursorRoot) return;
|
|
||||||
|
|
||||||
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
const finePointer = window.matchMedia('(pointer: fine)').matches;
|
|
||||||
const noHover = window.matchMedia('(hover: none)').matches;
|
|
||||||
|
|
||||||
/* ─── Custom sigil cursor + fading trail ─── */
|
|
||||||
const cursor = cursorRoot.querySelector('.cs-cursor') as HTMLElement | null;
|
|
||||||
if (cursor && finePointer && !noHover) {
|
|
||||||
root.classList.add('cs-cursor-on');
|
|
||||||
let cx = window.innerWidth / 2;
|
|
||||||
let cy = window.innerHeight / 2;
|
|
||||||
let raf = 0;
|
|
||||||
let lastTrail = 0;
|
|
||||||
const HOT = 'a,button,input,textarea,select,[role="button"],.btn,.plate,.topbar-control,.back-link,.chip';
|
|
||||||
|
|
||||||
function paint() {
|
|
||||||
raf = 0;
|
|
||||||
cursor!.style.transform = `translate3d(${cx}px, ${cy}px, 0)`;
|
|
||||||
}
|
|
||||||
window.addEventListener(
|
|
||||||
'mousemove',
|
|
||||||
(e) => {
|
|
||||||
cx = e.clientX;
|
|
||||||
cy = e.clientY;
|
|
||||||
if (!raf) raf = requestAnimationFrame(paint);
|
|
||||||
|
|
||||||
const t = e.target as Element | null;
|
|
||||||
const hot = !!(t && t.closest && t.closest(HOT));
|
|
||||||
cursor!.classList.toggle('cs-cursor--hot', hot);
|
|
||||||
|
|
||||||
if (!reduced && e.timeStamp - lastTrail > 28) {
|
|
||||||
lastTrail = e.timeStamp;
|
|
||||||
const dot = document.createElement('span');
|
|
||||||
dot.className = 'cs-trail';
|
|
||||||
dot.style.left = cx + 'px';
|
|
||||||
dot.style.top = cy + 'px';
|
|
||||||
cursorRoot!.appendChild(dot);
|
|
||||||
dot.addEventListener('animationend', () => dot.remove(), { once: true });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ passive: true }
|
|
||||||
);
|
|
||||||
window.addEventListener('mousedown', () => cursor!.classList.add('cs-cursor--down'));
|
|
||||||
window.addEventListener('mouseup', () => cursor!.classList.remove('cs-cursor--down'));
|
|
||||||
document.addEventListener('mouseleave', () => cursor!.classList.add('cs-cursor--gone'));
|
|
||||||
document.addEventListener('mouseenter', () => cursor!.classList.remove('cs-cursor--gone'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Scroll-entry databend on images ─── */
|
/* ─── Scroll-entry databend on images ─── */
|
||||||
if (!reduced && 'IntersectionObserver' in window) {
|
if (!reduced && 'IntersectionObserver' in window) {
|
||||||
|
|||||||
@@ -1890,7 +1890,6 @@ input[type="date"] { color-scheme: light; }
|
|||||||
--font-display: 'VT323', 'Space Mono', 'Courier New', monospace;
|
--font-display: 'VT323', 'Space Mono', 'Courier New', monospace;
|
||||||
--cs-corner: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'><path stroke-width='2.4' d='M3 3 C 26 10 33 26 36 44 C 38 60 46 70 60 78 C 74 86 84 86 97 84 M16 7 C 22 2 30 1 40 2 M14 17 C 8 24 5 33 4 45 M35 40 C 45 36 56 37 66 41 M34 49 C 30 60 30 71 33 83 M52 73 C 60 66 70 64 82 65 M58 80 C 55 90 56 97 60 99'/><path stroke-width='1' opacity='0.8' d='M24 9 L30 3 M10 31 L3 34 M41 38 L47 31 M33 61 L26 66 M71 66 L79 61 M49 55 L44 49 M22 24 L17 20'/></svg>");
|
--cs-corner: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'><path stroke-width='2.4' d='M3 3 C 26 10 33 26 36 44 C 38 60 46 70 60 78 C 74 86 84 86 97 84 M16 7 C 22 2 30 1 40 2 M14 17 C 8 24 5 33 4 45 M35 40 C 45 36 56 37 66 41 M34 49 C 30 60 30 71 33 83 M52 73 C 60 66 70 64 82 65 M58 80 C 55 90 56 97 60 99'/><path stroke-width='1' opacity='0.8' d='M24 9 L30 3 M10 31 L3 34 M41 38 L47 31 M33 61 L26 66 M71 66 L79 61 M49 55 L44 49 M22 24 L17 20'/></svg>");
|
||||||
--cs-barb: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 22' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M2 11 C 24 4 40 18 60 11 C 80 4 96 18 118 11'/><path stroke-width='1.3' d='M18 8 L22 1 M30 13 L27 21 M48 12 L48 2 M60 11 L60 1 M72 12 L76 20 M90 9 L87 1 M104 13 L108 21'/></svg>");
|
--cs-barb: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 22' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M2 11 C 24 4 40 18 60 11 C 80 4 96 18 118 11'/><path stroke-width='1.3' d='M18 8 L22 1 M30 13 L27 21 M48 12 L48 2 M60 11 L60 1 M72 12 L76 20 M90 9 L87 1 M104 13 L108 21'/></svg>");
|
||||||
--cs-cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 36 36' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><path d='M18 1 L18 11 M18 25 L18 35 M1 18 L11 18 M25 18 L35 18 M18 1 L14 6 M18 1 L22 6 M18 35 L14 30 M18 35 L22 30 M1 18 L6 14 M1 18 L6 22 M35 18 L30 14 M35 18 L30 22'/><path fill='%23fff' stroke='none' d='M18 13 L23 18 L18 23 L13 18 Z'/></svg>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Heads — VT323 bitmap, hard, uppercase, slight tracking so the dot-matrix
|
/* Heads — VT323 bitmap, hard, uppercase, slight tracking so the dot-matrix
|
||||||
@@ -1940,8 +1939,7 @@ html.cybersigil body::after {
|
|||||||
* Inert everywhere; only the cybersigil theme switches it on. Decorative
|
* Inert everywhere; only the cybersigil theme switches it on. Decorative
|
||||||
* layers ride above content at low opacity (pointer-events:none); the sigil
|
* layers ride above content at low opacity (pointer-events:none); the sigil
|
||||||
* cursor sits on top of everything. */
|
* cursor sits on top of everything. */
|
||||||
.cs-fx,
|
.cs-fx { display: none; }
|
||||||
.cs-cursor-root { display: none; }
|
|
||||||
.cybersigil .cs-fx {
|
.cybersigil .cs-fx {
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -2024,88 +2022,6 @@ html.cybersigil body::after {
|
|||||||
.cybersigil .cs-fx-corner--bl { bottom: 0; left: 0; transform: scaleY(-1); animation-delay: -3.4s; }
|
.cybersigil .cs-fx-corner--bl { bottom: 0; left: 0; transform: scaleY(-1); animation-delay: -3.4s; }
|
||||||
.cybersigil .cs-fx-corner--br { bottom: 0; right: 0; transform: scale(-1); animation-delay: -5.1s; }
|
.cybersigil .cs-fx-corner--br { bottom: 0; right: 0; transform: scale(-1); animation-delay: -5.1s; }
|
||||||
|
|
||||||
/* ─── Sigil crosshair cursor + fading trail ───
|
|
||||||
* Lives in its own un-contained, max-z root (CyberFx.astro) so it floats
|
|
||||||
* above every modal/library (Search + AssetManager are z-[200]). A solid
|
|
||||||
* bright core dot gives a precise aim point; a black hairline + colored
|
|
||||||
* bloom keep the sigil legible on dark void AND light asset thumbnails. */
|
|
||||||
.cybersigil .cs-cursor-root {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 2147483647;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.cybersigil .cs-cursor {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 42px;
|
|
||||||
height: 42px;
|
|
||||||
margin: -21px 0 0 -21px;
|
|
||||||
opacity: 0;
|
|
||||||
will-change: transform;
|
|
||||||
transition: opacity 0.16s linear;
|
|
||||||
}
|
|
||||||
html.cs-cursor-on.cybersigil,
|
|
||||||
html.cs-cursor-on.cybersigil * { cursor: none !important; }
|
|
||||||
html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
|
|
||||||
.cybersigil .cs-cursor-ring {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background-color: var(--sky);
|
|
||||||
-webkit-mask: var(--cs-cursor) center / contain no-repeat;
|
|
||||||
mask: var(--cs-cursor) center / contain no-repeat;
|
|
||||||
filter:
|
|
||||||
drop-shadow(0 0 1px #000)
|
|
||||||
drop-shadow(0 0 1px #000)
|
|
||||||
drop-shadow(0 0 6px color-mix(in srgb, var(--sky) 80%, transparent));
|
|
||||||
transition: transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
||||||
background-color 0.12s linear, filter 0.12s linear;
|
|
||||||
}
|
|
||||||
.cybersigil .cs-cursor-core {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
margin: -3px 0 0 -3px;
|
|
||||||
background: var(--rosewater);
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 1.5px var(--crust),
|
|
||||||
0 0 7px 1px var(--mauve);
|
|
||||||
transition: background-color 0.12s linear, box-shadow 0.12s linear,
|
|
||||||
transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
||||||
}
|
|
||||||
.cybersigil .cs-cursor--hot .cs-cursor-ring {
|
|
||||||
background-color: var(--mauve);
|
|
||||||
transform: scale(1.3) rotate(45deg);
|
|
||||||
filter:
|
|
||||||
drop-shadow(0 0 1px #000)
|
|
||||||
drop-shadow(0 0 1px #000)
|
|
||||||
drop-shadow(0 0 9px color-mix(in srgb, var(--mauve) 85%, transparent));
|
|
||||||
}
|
|
||||||
.cybersigil .cs-cursor--hot .cs-cursor-core {
|
|
||||||
background: var(--sky);
|
|
||||||
box-shadow: 0 0 0 1.5px var(--crust), 0 0 9px 2px var(--sky);
|
|
||||||
transform: scale(1.25);
|
|
||||||
}
|
|
||||||
.cybersigil .cs-cursor--down .cs-cursor-ring { transform: scale(0.8); }
|
|
||||||
.cybersigil .cs-cursor--hot.cs-cursor--down .cs-cursor-ring { transform: scale(1.05) rotate(45deg); }
|
|
||||||
.cybersigil .cs-cursor--down .cs-cursor-core { transform: scale(0.7); }
|
|
||||||
.cybersigil .cs-cursor--gone { opacity: 0; }
|
|
||||||
.cybersigil .cs-trail {
|
|
||||||
position: fixed;
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
margin: -3px 0 0 -3px;
|
|
||||||
pointer-events: none;
|
|
||||||
background: var(--sky);
|
|
||||||
box-shadow: 0 0 5px 1px color-mix(in srgb, var(--sky) 70%, transparent);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
animation: cs-trail-fade 460ms linear forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Selection — magenta block, bone glyph, cyan bleed. */
|
/* Selection — magenta block, bone glyph, cyan bleed. */
|
||||||
.cybersigil ::selection {
|
.cybersigil ::selection {
|
||||||
background: var(--mauve);
|
background: var(--mauve);
|
||||||
@@ -3002,11 +2918,6 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
|
|||||||
81% { opacity: 0.2; }
|
81% { opacity: 0.2; }
|
||||||
82%, 100% { opacity: 0; }
|
82%, 100% { opacity: 0; }
|
||||||
}
|
}
|
||||||
@keyframes cs-trail-fade {
|
|
||||||
0% { opacity: 0.7; transform: rotate(45deg) scale(1); }
|
|
||||||
100% { opacity: 0; transform: rotate(45deg) scale(0.2); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ═══ Reduced motion — universal kill-switch. Final word in the file so it
|
/* ═══ Reduced motion — universal kill-switch. Final word in the file so it
|
||||||
* overrides every animation/transition above, all themes. Content still
|
* overrides every animation/transition above, all themes. Content still
|
||||||
* resolves to its final state (forwards-filled keyframes complete). ═══ */
|
* resolves to its final state (forwards-filled keyframes complete). ═══ */
|
||||||
|
|||||||
Reference in New Issue
Block a user