Skip to content

Commit

Permalink
chore(ux): add animated header with anime.js in p2p sections (mudler#…
Browse files Browse the repository at this point in the history
…3271)

feat(p2p): add animated header with anime.js

Signed-off-by: Ettore Di Giacinto <[email protected]>
  • Loading branch information
mudler authored Aug 19, 2024
1 parent e4c696d commit 13cb796
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 56 deletions.
73 changes: 73 additions & 0 deletions core/http/static/p2panimation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const canvas = document.getElementById('networkCanvas');
const ctx = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const particles = [];
const lines = [];

class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = 2 + Math.random() * 2;
this.color = `rgba(0, 255, 204, ${Math.random()})`;
this.speed = Math.random() * 2 + 1;
this.angle = Math.random() * Math.PI * 2;
}

update() {
this.x += Math.cos(this.angle) * this.speed;
this.y += Math.sin(this.angle) * this.speed;

if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
}
}

draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.fillStyle = this.color;
ctx.fill();
}
}

function connectParticles() {
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const distance = Math.hypot(particles[i].x - particles[j].x, particles[i].y - particles[j].y);
if (distance < 150) {
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(0, 255, 204, ${1 - distance / 150})`;
ctx.stroke();
}
}
}
}

function initParticles(num) {
for (let i = 0; i < num; i++) {
particles.push(new Particle(Math.random() * canvas.width, Math.random() * canvas.height));
}
}

function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

particles.forEach(particle => {
particle.update();
particle.draw();
});

connectParticles();

requestAnimationFrame(animate);
}

initParticles(100);
animate();
62 changes: 19 additions & 43 deletions core/http/views/explorer.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,54 +155,29 @@
right: 10px;
color: #e2e8f0;
}
.fa-circle-nodes {
/* font-size: 100px; /* Adjust the size as needed */
animation: rotateCircleNodes 8s linear infinite; /* Slow and fluid rotation */
display: inline-block;
}

@keyframes rotateCircleNodes {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Animation for the warning box */
.fa-flask {
/* font-size: 100px; /* Adjust the size as needed */
animation: shakeFlask 3s ease-in-out infinite; /* Smooth easing and longer duration for fluidity */
transform-origin: bottom center;
}

@keyframes shakeFlask {
0%, 10% { transform: rotate(0deg); } /* Start and end still */
20% { transform: rotate(-10deg); } /* Smooth transition to left */
30% { transform: rotate(10deg); } /* Smooth transition to right */
40% { transform: rotate(-8deg); } /* Smooth transition to left */
50% { transform: rotate(8deg); } /* Smooth transition to right */
60% { transform: rotate(-5deg); } /* Smooth transition to left */
70% { transform: rotate(5deg); } /* Smooth transition to right */
80% { transform: rotate(-2deg); } /* Smooth transition to left */
90% { transform: rotate(2deg); } /* Smooth transition to right */
100% { transform: rotate(0deg); } /* Return to center */
}
</style>

<body class="bg-gray-900 text-gray-200">
<div class="flex flex-col min-h-screen" x-data="networkClusters()" x-init="init()">
{{template "views/partials/navbar_explorer" .}}

<header class="text-center py-12">
<h1 class="text-5xl font-bold text-gray-100">
<i class="fa-solid fa-circle-nodes mr-2"></i> Network Clusters Explorer

</h1>
<p class="mt-4 text-lg">
View the clusters and workers available in each network.
<a href="https://localai.io/features/distribute/" target="_blank">
<i class="fas fa-circle-info pr-2"></i>
</a>
</p>

</header>
<div class="animation-container">
<canvas id="networkCanvas"></canvas>
<div class="text-overlay">
<header class="text-center py-12">
<h1 class="text-5xl font-bold text-gray-100">
<i class="fa-solid fa-circle-nodes mr-2"></i> Network Clusters Explorer

</h1>
<p class="mt-4 text-lg">
View the clusters and workers available in each network.
<a href="https://localai.io/features/distribute/" target="_blank">
<i class="fas fa-circle-info pr-2"></i>
</a>
</p>

</header>
</div>
</div>

<div class="container mx-auto px-4 flex-grow">
<!-- Warning Box -->
Expand Down Expand Up @@ -395,6 +370,7 @@ <h2 class="text-3xl font-bold mb-4 mt-4">Available Clusters in this network</h2>
}
}
</script>
<script src="/static/p2panimation.js"></script>

{{template "views/partials/footer" .}}
</div>
Expand Down
26 changes: 18 additions & 8 deletions core/http/views/p2p.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@
{{template "views/partials/navbar" .}}
<div class="container mx-auto px-4 flex-grow">
<div class="workers mt-12 text-center">

<h2 class="text-3xl font-semibold text-gray-100 mb-8">
<i class="fa-solid fa-circle-nodes"></i> Distributed inference with P2P
<a href="https://localai.io/features/distribute/" target="_blank">
<i class="fas fa-circle-info pr-2"></i>
</a>
</h2>
<div class="animation-container">
<canvas id="networkCanvas"></canvas>
<div class="text-overlay">
<header class="text-center py-12">
<h1 class="text-5xl font-bold text-gray-100">
<i class="fa-solid fa-circle-nodes mr-2"></i> Distributed inference with P2P
</h1>
<p class="mt-4 text-lg">
Distribute computation by sharing and loadbalancing instances or sharding model weights.
<a href="https://localai.io/features/distribute/" target="_blank">
<i class="fas fa-circle-info pr-2"></i>
</a>
</p>

</header>
</div>
</div>
<h5 class="mb-4 text-justify">LocalAI uses P2P technologies to enable distribution of work between peers. It is possible to share an instance with Federation and/or split the weights of a model across peers (only available with llama.cpp models). You can now share computational resources between your devices or your friends!</h5>
<!-- Warning box if p2p token is empty and p2p is enabled -->
{{ if and .IsP2PEnabled (eq .P2PToken "") }}
Expand Down Expand Up @@ -144,7 +154,7 @@ <h3 class="text-2xl font-semibold text-gray-100 mb-6"><i class="fa-solid fa-book

{{template "views/partials/footer" .}}
</div>

<script src="/static/p2panimation.js"></script>
<style>
.token {
word-break: break-all;
Expand Down
69 changes: 65 additions & 4 deletions core/http/views/partials/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
rel="stylesheet"
href="/static/assets/highlightjs.css"
/>
<script defer src="/static/assets/anime.min.js"></script>
<script
defer
src="/static/assets/highlightjs.js"
Expand Down Expand Up @@ -47,8 +48,68 @@
},
};
</script>
<link href="/static/assets/fontawesome/css/fontawesome.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/brands.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/solid.css" rel="stylesheet" />
<script src="/static/assets/htmx.js" crossorigin="anonymous"></script>
<link href="/static/assets/fontawesome/css/fontawesome.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/brands.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/solid.css" rel="stylesheet" />
<script src="/static/assets/htmx.js" crossorigin="anonymous"></script>
<!-- P2P Animation START -->
<style>
.animation-container {
position: relative;
width: 100%;
height: 25vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}

canvas {
position: absolute;
top: 0;
left: 0;
}

.text-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
z-index: 1;
}
</style>
<!-- P2P Animation END -->
<!-- Flask and node animation -->
<style>
.fa-circle-nodes {
/* font-size: 100px; /* Adjust the size as needed */
animation: rotateCircleNodes 8s linear infinite; /* Slow and fluid rotation */
display: inline-block;
}

@keyframes rotateCircleNodes {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Animation for the warning box */
.fa-flask {
/* font-size: 100px; /* Adjust the size as needed */
animation: shakeFlask 3s ease-in-out infinite; /* Smooth easing and longer duration for fluidity */
transform-origin: bottom center;
}

@keyframes shakeFlask {
0%, 10% { transform: rotate(0deg); } /* Start and end still */
20% { transform: rotate(-10deg); } /* Smooth transition to left */
30% { transform: rotate(10deg); } /* Smooth transition to right */
40% { transform: rotate(-8deg); } /* Smooth transition to left */
50% { transform: rotate(8deg); } /* Smooth transition to right */
60% { transform: rotate(-5deg); } /* Smooth transition to left */
70% { transform: rotate(5deg); } /* Smooth transition to right */
80% { transform: rotate(-2deg); } /* Smooth transition to left */
90% { transform: rotate(2deg); } /* Smooth transition to right */
100% { transform: rotate(0deg); } /* Return to center */
}
</style>
</head>
4 changes: 3 additions & 1 deletion embedded/webui_static.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,6 @@
- filename: "KFOlCnqEu92Fr1MmYUtfBBc9.ttf"
url: "https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfBBc9.ttf"
sha: "361a50f8a6c816ba4306c5290b7e487a726e1b4dcc3d8d7e4acf1fc2dae9f551"

- filename: "anime.js"
url: "https://raw.githubusercontent.com/juliangarnier/anime/master/lib/anime.min.js"
sha: "bceef94f964481f7680d95e7fbbe5a8c20d3945a926a754874898a578db7c7ab"

0 comments on commit 13cb796

Please sign in to comment.