chore: improve splash screen with randomized animation of cursor-movement

This commit is contained in:
E44
2026-01-09 21:30:46 +01:00
parent 89ce7402df
commit 09adf5dba4
2 changed files with 432 additions and 225 deletions
+5 -1
View File
@@ -20,6 +20,8 @@
import { on_start } from '$lib/ts/main'; import { on_start } from '$lib/ts/main';
import { display_status_to_info } from '$lib/ts/utils'; import { display_status_to_info } from '$lib/ts/utils';
import HighlightedText from '$lib/components/HighlightedText.svelte'; import HighlightedText from '$lib/components/HighlightedText.svelte';
import { dev } from '$app/environment';
import SplashScreen from './../../../../shared/splash_screen.html?raw';
const ip_regex = const ip_regex =
/^(?:(?:10|127)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)|192\.168\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)|172\.(?:1[6-9]|2\d|3[0-1])\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d))$/; /^(?:(?:10|127)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)|192\.168\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d)|172\.(?:1[6-9]|2\d|3[0-1])\.(?:25[0-5]|2[0-4]\d|1?\d?\d)\.(?:25[0-5]|2[0-4]\d|1?\d?\d))$/;
@@ -221,7 +223,9 @@
{/snippet} {/snippet}
<main class="bg-stone-900 h-dvh w-dvw text-stone-200 px-4 py-2 gap-2 grid grid-rows-[3rem_auto]"> <main class="bg-stone-900 h-dvh w-dvw text-stone-200 px-4 py-2 gap-2 grid grid-rows-[3rem_auto]">
<!-- {@html SplashScreen} --> {#if dev}
{@html SplashScreen}
{/if}
<div class="w-[calc(100dvw-(8*var(--spacing)))] flex justify-between"> <div class="w-[calc(100dvw-(8*var(--spacing)))] flex justify-between">
<span class="text-4xl font-bold content-center pl-1"> PLG MuDiCS </span> <span class="text-4xl font-bold content-center pl-1"> PLG MuDiCS </span>
+427 -224
View File
@@ -1,267 +1,470 @@
<div id="splash"> <div id="splash">
<svg id="splash-svg" viewBox="0 0 950 550"> <svg id="splash-svg" class="fade-in" viewBox="0 0 950 550">
<!-- Paths --> <!-- Paths -->
<!-- Disabled Paths --> <!-- Disabled Paths -->
<path class="splash-stroke" d="M 385 350 V 270 H 100 V 112.5" /> <path class="splash-stroke" d="M 385 350 V 270 H 100 V 112.5" />
<path class="splash-stroke" d="M 445 350 V 210 H 350 V 112.5" /> <path class="splash-stroke" d="M 445 350 V 210 H 350 V 112.5" />
<path class="splash-stroke" d="M 505 350 V 210 H 600 V 112.5" /> <path class="splash-stroke" d="M 505 350 V 210 H 600 V 112.5" />
<path class="splash-stroke" d="M 565 350 V 270 H 850 V 112.5" /> <path class="splash-stroke" d="M 565 350 V 270 H 850 V 112.5" />
<!-- Masks --> <!-- Masks -->
<defs> <defs>
<mask id="m1" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> <mask
<path class="splash-mask" pathLength="100" d="M 385 350 V 270 H 100 V 112.5" /> id="m1"
</mask> maskUnits="userSpaceOnUse"
<mask id="m2" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> maskContentUnits="userSpaceOnUse"
<path class="splash-mask" pathLength="100" d="M 445 350 V 210 H 350 V 112.5" /> >
</mask> <path
<mask id="m3" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> class="splash-mask"
<path class="splash-mask" pathLength="100" d="M 505 350 V 210 H 600 V 112.5" /> pathLength="100"
</mask> d="M 385 350 V 270 H 100 V 112.5"
<mask id="m4" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> />
<path class="splash-mask" pathLength="100" d="M 565 350 V 270 H 850 V 112.5" /> </mask>
</mask> <mask
</defs> id="m2"
<!-- Active Paths --> maskUnits="userSpaceOnUse"
<path class="splash-stroke-active" mask="url(#m1)" d="M 385 350 V 270 H 100 V 112.5" /> maskContentUnits="userSpaceOnUse"
<path class="splash-stroke-active" mask="url(#m2)" d="M 445 350 V 210 H 350 V 112.5" /> >
<path class="splash-stroke-active" mask="url(#m3)" d="M 505 350 V 210 H 600 V 112.5" /> <path
<path class="splash-stroke-active" mask="url(#m4)" d="M 565 350 V 270 H 850 V 112.5" /> class="splash-mask"
pathLength="100"
d="M 445 350 V 210 H 350 V 112.5"
/>
</mask>
<mask
id="m3"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse"
>
<path
class="splash-mask"
pathLength="100"
d="M 505 350 V 210 H 600 V 112.5"
/>
</mask>
<mask
id="m4"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse"
>
<path
class="splash-mask"
pathLength="100"
d="M 565 350 V 270 H 850 V 112.5"
/>
</mask>
</defs>
<!-- Active Paths -->
<path
class="splash-stroke-active"
mask="url(#m1)"
d="M 385 350 V 270 H 100 V 112.5"
/>
<path
class="splash-stroke-active"
mask="url(#m2)"
d="M 445 350 V 210 H 350 V 112.5"
/>
<path
class="splash-stroke-active"
mask="url(#m3)"
d="M 505 350 V 210 H 600 V 112.5"
/>
<path
class="splash-stroke-active"
mask="url(#m4)"
d="M 565 350 V 270 H 850 V 112.5"
/>
<!-- Displays --> <!-- Displays -->
<rect x="0" y="0" width="200" height="112.5" rx="8" ry="8" class="splash-monitor" /> <rect
<rect x="250" y="0" width="200" height="112.5" rx="8" ry="8" class="splash-monitor" /> x="0"
<rect x="500" y="0" width="200" height="112.5" rx="8" ry="8" class="splash-monitor" /> y="0"
<rect x="750" y="0" width="200" height="112.5" rx="8" ry="8" class="splash-monitor" /> width="200"
height="112.5"
rx="8"
ry="8"
class="splash-monitor"
/>
<rect
x="250"
y="0"
width="200"
height="112.5"
rx="8"
ry="8"
class="splash-monitor"
/>
<rect
x="500"
y="0"
width="200"
height="112.5"
rx="8"
ry="8"
class="splash-monitor"
/>
<rect
x="750"
y="0"
width="200"
height="112.5"
rx="8"
ry="8"
class="splash-monitor"
/>
<!-- Text --> <!-- Text -->
<text class="splash-text" x="100" y="66.25" font-size="90">Mu</text> <text class="splash-text" x="100" y="66.25" font-size="90">Mu</text>
<text class="splash-text" x="350" y="66.25" font-size="90">Di</text> <text class="splash-text" x="350" y="66.25" font-size="90">Di</text>
<text class="splash-text" x="600" y="66.25" font-size="90">C</text> <text class="splash-text" x="600" y="66.25" font-size="90">C</text>
<text class="splash-text" x="850" y="66.25" font-size="90">S</text> <text class="splash-text" x="850" y="66.25" font-size="90">S</text>
<!-- Controller --> <!-- Controller -->
<rect x="325" y="350" width="300" height="168.75" rx="8" ry="8" class="splash-control-monitor" /> <rect
<rect x="335" y="390" width="135" height="120" rx="8" ry="8" class="splash-other-button" /> x="325"
<rect x="480" y="390" width="135" height="55" rx="8" ry="8" class="splash-other-button" /> y="350"
<rect x="480" y="455" width="135" height="55" rx="8" ry="8" class="splash-start-button" /> width="300"
height="168.75"
rx="8"
ry="8"
class="splash-control-monitor"
/>
<rect
x="335"
y="390"
width="135"
height="120"
rx="8"
ry="8"
class="splash-other-button"
/>
<rect
x="480"
y="390"
width="135"
height="55"
rx="8"
ry="8"
class="splash-other-button"
/>
<rect
x="480"
y="455"
width="135"
height="55"
rx="8"
ry="8"
class="splash-start-button"
/>
<!-- Window Controls --> <!-- Window Controls -->
<path class="window-controls" d="M 600 360 L 615 375" /> <path class="window-controls" d="M 600 360 l 15 15" />
<path class="window-controls" d="M 600 375 L 615 360" /> <path class="window-controls" d="M 600 375 l 15 -15" />
<path class="window-controls" fill="none" d="M 575 360 H 590 V 375 H 575 V 360" /> <path
<path class="window-controls" d="M 550 375 H 565" /> class="window-controls"
fill="none"
<svg class="cursor" width="50" height="50" viewBox="0 0 24 24" x="510" y="480" aria-hidden="true"> d="M 575 360 h 15 v 15 h -15 v -15"
<g stroke="#ffffff" fill="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> />
<path stroke="#000000" d="M 6.5 10 H 18 V 19 H 6" /> <path class="window-controls" d="M 550 375 h 15" />
<path d="M22 14a8 8 0 0 1-8 8" /> </svg>
<path d="M18 11v-1a2 2 0 0 0-2-2a2 2 0 0 0-2 2" /> <div class="fade-in">
<path d="M14 10V9a2 2 0 0 0-2-2a2 2 0 0 0-2 2v1" /> <div
<path d="M10 9.5V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v10" /> class="cursor-x"
<path style="
d="M18 11a2 2 0 1 1 4 0v3a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15" /> position: absolute;
</g> left: calc(50cqw + var(--mouse-start-x));
</svg> top: calc(50cqh + var(--mouse-start-y));
</svg> "
>
<svg class="cursor-y" width="50" height="50" viewBox="0 0 24 24">
<g
stroke="#ffffff"
fill="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="#000000" d="M 6.5 10 H 18 V 19 H 6" />
<path d="M22 14a8 8 0 0 1-8 8" />
<path d="M18 11v-1a2 2 0 0 0-2-2a2 2 0 0 0-2 2" />
<path d="M14 10V9a2 2 0 0 0-2-2a2 2 0 0 0-2 2v1" />
<path d="M10 9.5V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v10" />
<path
d="M18 11a2 2 0 1 1 4 0v3a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"
/>
</g>
</svg>
</div>
</div>
</div> </div>
<style> <style>
:root { :root {
--splash-fade-out-delay: 0s; --splash-fade-out-delay: 3.5s;
--splash-fade-out-state: running; --splash-fade-out-state: running;
--base-stroke: #444444; --base-stroke: #444444;
--base-stroke-active: #109e00; --base-stroke-active: #109e00;
--splash-bg: oklch(21.6% 0.006 56.043); --splash-bg: oklch(21.6% 0.006 56.043);
--monitor-dark: #000000; --monitor-dark: #000000;
--monitor-active: #ffffff; --monitor-active: #ffffff;
--window-controls: #cccccc; --window-controls: #cccccc;
--start-button-inactive: #cccccc; --start-button-inactive: #cccccc;
--start-button-hover: #77a3b1; --start-button-hover: #77a3b1;
--start-button-active: #2c819b; --start-button-active: #2c819b;
--other-button: oklch(55.3% 0.013 58.071); --other-button: oklch(55.3% 0.013 58.071);
--splash-control-monitor: oklch(44.4% 0.011 73.639); --splash-control-monitor: oklch(44.4% 0.011 73.639);
--stroke-strength: 8; --mouse-size: 50px;
--dash: 16; --mouse-bounce-delay: 5s;
--gap: 20; --mouse-start-x: calc((35 * 100vw) / 1920);
} --mouse-start-y: calc((60 * 100vh) / 1080);
--dur-x: 16s;
--dur-y: 9s;
#splash { --stroke-strength: 8;
position: fixed; --dash: 16;
inset: 0; --gap: 20;
background: var(--splash-bg); }
color: white;
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
/* animation: splash-fade 1s ease 4s forwards; */
height: 100vh;
width: 100vw;
animation-name: splash-fade; #splash {
animation-duration: 1s; position: fixed;
animation-timing-function: ease; inset: 0;
animation-fill-mode: forwards; background: var(--splash-bg);
animation-delay: var(--splash-fade-out-delay); color: white;
animation-play-state: var(--splash-fade-out-state); display: flex;
} align-items: center;
justify-content: center;
z-index: 9999;
height: 100vh;
width: 100vw;
#splash-svg { animation-name: splash-fade;
max-height: 50vh; animation-duration: 1s;
max-width: 80vw; animation-timing-function: ease;
opacity: 0; animation-fill-mode: forwards;
animation: fade-in 1s ease 500ms forwards; animation-delay: var(--splash-fade-out-delay);
} animation-play-state: var(--splash-fade-out-state);
}
.splash-monitor { #splash-svg {
aspect-ratio: 16/9; max-height: 50vh;
rx: 8; max-width: 80vw;
ry: 8; transform: translateY(-12cqh);
width: 200; }
fill: var(--monitor-dark);
}
.splash-control-monitor { .fade-in {
fill: var(--splash-control-monitor); opacity: 0;
} animation: fade-in 1s ease 500ms forwards;
}
.splash-other-button { .splash-monitor {
fill: var(--other-button); aspect-ratio: 16/9;
} rx: 8;
ry: 8;
width: 200;
fill: var(--monitor-dark);
}
.splash-stroke, .splash-control-monitor {
.splash-stroke-active { fill: var(--splash-control-monitor);
fill: none; }
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: var(--stroke-strength);
stroke-dasharray: var(--dash) var(--gap);
}
.window-controls { .splash-other-button {
stroke: var(--window-controls); fill: var(--other-button);
stroke-width: 3; }
}
.splash-stroke { .splash-stroke,
stroke: var(--base-stroke); .splash-stroke-active {
} fill: none;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: var(--stroke-strength);
stroke-dasharray: var(--dash) var(--gap);
}
.splash-stroke-active { .window-controls {
stroke: var(--base-stroke-active); stroke: var(--window-controls);
} stroke-width: 3;
}
.splash-mask { .splash-stroke {
fill: none; stroke: var(--base-stroke);
stroke: #fff; }
stroke-linecap: round;
stroke-width: var(--stroke-strength);
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 1s ease-in-out 1.35s forwards;
}
.splash-text { .splash-stroke-active {
text-anchor: middle; stroke: var(--base-stroke-active);
dominant-baseline: middle; }
fill: var(--monitor-dark);
user-select: none;
font-family: sans-serif;
}
.splash-monitor { .splash-mask {
fill: var(--monitor-dark); fill: none;
animation: activate-monitor 0ms ease 2.35s forwards; stroke: #fff;
} stroke-linecap: round;
stroke-width: var(--stroke-strength);
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 1s ease-in-out 1.35s forwards;
}
.splash-start-button { .splash-text {
fill: var(--start-button-inactive); text-anchor: middle;
animation: start-button-hover-press 1s ease-in-out 450ms forwards; dominant-baseline: middle;
} fill: var(--monitor-dark);
user-select: none;
font-family: sans-serif;
}
.cursor { .splash-monitor {
animation: move-mouse 1s ease-in-out 0ms forwards; fill: var(--monitor-dark);
} animation: activate-monitor 0ms ease 2.35s forwards;
}
@keyframes fade-in { .splash-start-button {
to { fill: var(--start-button-inactive);
opacity: 1; animation: start-button-hover-press 1s ease-in-out 450ms forwards;
} }
}
@keyframes move-mouse { .cursor-x {
0% { animation-name: move-mouse, mouse-bounceX;
transform: translateX(-100px); animation-duration: 1s, var(--dur-x);
} animation-delay: 0s, var(--mouse-bounce-delay);
animation-iteration-count: 1, infinite;
animation-direction: normal, normal;
animation-timing-function: ease-in-out, linear;
animation-fill-mode: both, none;
will-change: transform;
}
50% { .cursor-y {
transform: translateX(-100px); animation-name: mouse-bounceY;
} animation-duration: var(--dur-y);
animation-delay: var(--mouse-bounce-delay);
animation-iteration-count: infinite;
animation-direction: normal;
animation-timing-function: linear;
animation-fill-mode: none;
will-change: transform;
}
100% { @keyframes fade-in {
transform: translateX(0px); to {
} opacity: 1;
} }
}
@keyframes start-button-hover-press { @keyframes move-mouse {
0% { 0% {
fill: var(--start-button-inactive); transform: translateX(-100px);
} }
30% { 50% {
fill: var(--start-button-inactive); transform: translateX(-100px);
} }
40% { 100% {
fill: var(--start-button-hover); transform: translateX(0px);
} }
}
70% { @keyframes mouse-bounceX {
fill: var(--start-button-hover); 0% {
} transform: translateX(0);
}
80% { 26% {
fill: var(--start-button-active); transform: translateX(calc(-50cqw - var(--mouse-start-x)));
} }
90% { 76% {
fill: var(--start-button-active); transform: translateX(
} calc(50cqw - var(--mouse-size) - var(--mouse-start-x))
);
}
}
100% { @keyframes mouse-bounceY {
fill: var(--start-button-hover); 0% {
} transform: translateY(0);
} }
@keyframes draw { 27% {
to { transform: translateY(calc(-50cqh - var(--mouse-start-y)));
stroke-dashoffset: 0; }
}
}
@keyframes activate-monitor { 77% {
to { transform: translateY(
fill: var(--monitor-active); calc(50cqh - var(--mouse-size) - var(--mouse-start-y))
} );
} }
}
@keyframes splash-fade { @keyframes start-button-hover-press {
to { 0% {
opacity: 0; fill: var(--start-button-inactive);
visibility: hidden; }
}
}
rect { 30% {
vector-effect: non-scaling-stroke; fill: var(--start-button-inactive);
} }
/* verhindert, dass die Linien beim Skalieren dicker werden */ 40% {
.cursor * { fill: var(--start-button-hover);
vector-effect: non-scaling-stroke; }
}
</style> 70% {
fill: var(--start-button-hover);
}
80% {
fill: var(--start-button-active);
}
90% {
fill: var(--start-button-active);
}
100% {
fill: var(--start-button-hover);
}
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
@keyframes activate-monitor {
to {
fill: var(--monitor-active);
}
}
@keyframes splash-fade {
to {
opacity: 0;
visibility: hidden;
}
}
rect {
vector-effect: non-scaling-stroke;
}
/* verhindert, dass die Linien beim Skalieren dicker werden */
.cursor * {
vector-effect: non-scaling-stroke;
}
</style>
<script>
const r =
Math.random() < 0.01
? 9 / 15.039473684
: 0.55 + (Math.random() - 0.5) * 0.18;
const tx = 13 + Math.random() * 5;
document.documentElement.style.setProperty("--dur-x", tx + "s");
document.documentElement.style.setProperty("--dur-y", tx * r + "s");
</script>