Enhance Neural Network Background Animation: Introduce subtle flowing network aesthetics with improved color schemes and animations. Update canvas handling to ensure proper layering and visibility. Implement new flow animations along connections for a more dynamic visual experience. Adjust node and connection properties for a cleaner, more organic look. Ensure compatibility with dark mode and optimize rendering methods for both WebGL and Canvas. Update styles to maintain transparency across themes.
This commit is contained in:
BIN
ChatGPT Image 20. Apr. 2025, 09_02_47.png
Normal file
BIN
ChatGPT Image 20. Apr. 2025, 09_02_47.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
47
website/static/css/neural-network-background.css
Normal file
47
website/static/css/neural-network-background.css
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* Neural Network Background CSS */
|
||||||
|
|
||||||
|
/* Make sure the neural network background is always visible */
|
||||||
|
#neural-network-background {
|
||||||
|
position: fixed !important;
|
||||||
|
top: 0 !important;
|
||||||
|
left: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
z-index: -10 !important; /* Below content but above regular background */
|
||||||
|
pointer-events: none !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override any solid background colors for the body */
|
||||||
|
body, body.dark {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure any background color is removed */
|
||||||
|
html.dark, html {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure any fixed backgrounds are removed */
|
||||||
|
#app-container {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure content is properly visible over the background */
|
||||||
|
.glass-morphism {
|
||||||
|
background-color: rgba(17, 24, 39, 0.6) !important;
|
||||||
|
backdrop-filter: blur(5px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .glass-navbar-dark {
|
||||||
|
background-color: rgba(10, 14, 25, 0.7) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .glass-navbar-light {
|
||||||
|
background-color: rgba(255, 255, 255, 0.7) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure footer has proper transparency */
|
||||||
|
footer {
|
||||||
|
background-color: rgba(10, 14, 25, 0.7) !important;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Neural Network Background Animation
|
* Neural Network Background Animation
|
||||||
* Modern, darker, mystical theme using WebGL
|
* Modern, darker, mystical theme using WebGL
|
||||||
|
* Subtle flowing network aesthetic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NeuralNetworkBackground {
|
class NeuralNetworkBackground {
|
||||||
@@ -13,11 +14,22 @@ class NeuralNetworkBackground {
|
|||||||
this.canvas.style.left = '0';
|
this.canvas.style.left = '0';
|
||||||
this.canvas.style.width = '100%';
|
this.canvas.style.width = '100%';
|
||||||
this.canvas.style.height = '100%';
|
this.canvas.style.height = '100%';
|
||||||
this.canvas.style.zIndex = '-5';
|
this.canvas.style.zIndex = '-10'; // Ensure it's behind content but visible
|
||||||
this.canvas.style.pointerEvents = 'none';
|
this.canvas.style.pointerEvents = 'none';
|
||||||
|
this.canvas.style.opacity = '1'; // Force visibility
|
||||||
|
|
||||||
// Append to body
|
// If canvas already exists, remove it first
|
||||||
|
const existingCanvas = document.getElementById('neural-network-background');
|
||||||
|
if (existingCanvas) {
|
||||||
|
existingCanvas.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to body as first child to ensure it's behind everything
|
||||||
|
if (document.body.firstChild) {
|
||||||
|
document.body.insertBefore(this.canvas, document.body.firstChild);
|
||||||
|
} else {
|
||||||
document.body.appendChild(this.canvas);
|
document.body.appendChild(this.canvas);
|
||||||
|
}
|
||||||
|
|
||||||
// WebGL context
|
// WebGL context
|
||||||
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl');
|
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl');
|
||||||
@@ -33,16 +45,17 @@ class NeuralNetworkBackground {
|
|||||||
// Animation properties
|
// Animation properties
|
||||||
this.nodes = [];
|
this.nodes = [];
|
||||||
this.connections = [];
|
this.connections = [];
|
||||||
|
this.flows = []; // Flow animations along connections
|
||||||
this.animationFrameId = null;
|
this.animationFrameId = null;
|
||||||
this.isDarkMode = document.documentElement.classList.contains('dark');
|
this.isDarkMode = true; // Always use dark mode for the background
|
||||||
|
|
||||||
// Colors - using hex values for better control
|
// Colors - Updated to be more subtle
|
||||||
this.darkModeColors = {
|
this.darkModeColors = {
|
||||||
background: '#0a0e19',
|
background: '#050a14', // Darker blue-black background
|
||||||
nodeColor: '#6d28d9',
|
nodeColor: '#4a5568', // Darker nodes for subtlety
|
||||||
nodePulse: '#8b5cf6',
|
nodePulse: '#718096', // Subtle blue pulse
|
||||||
connectionColor: '#4c1d95',
|
connectionColor: '#2d3748', // Darker connections
|
||||||
glowColor: '#7c3aed'
|
flowColor: '#4a88ff80' // Semi-transparent flow highlight
|
||||||
};
|
};
|
||||||
|
|
||||||
this.lightModeColors = {
|
this.lightModeColors = {
|
||||||
@@ -50,18 +63,21 @@ class NeuralNetworkBackground {
|
|||||||
nodeColor: '#7c3aed',
|
nodeColor: '#7c3aed',
|
||||||
nodePulse: '#8b5cf6',
|
nodePulse: '#8b5cf6',
|
||||||
connectionColor: '#a78bfa',
|
connectionColor: '#a78bfa',
|
||||||
glowColor: '#c4b5fd'
|
flowColor: '#c4b5fd'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Config
|
// Config - Updated to be more flowing and subtle
|
||||||
this.config = {
|
this.config = {
|
||||||
nodeCount: 100,
|
nodeCount: 100, // Slightly fewer nodes for cleaner look
|
||||||
nodeSize: 2,
|
nodeSize: 0.8, // Smaller nodes
|
||||||
nodeVariation: 1.5,
|
nodeVariation: 0.5, // Less variation for uniformity
|
||||||
connectionDistance: 150,
|
connectionDistance: 200, // Longer connections for better flow
|
||||||
connectionOpacity: 0.2,
|
connectionOpacity: 0.2, // More subtle connections
|
||||||
animationSpeed: 0.3,
|
animationSpeed: 0.08, // Much slower movement
|
||||||
pulseSpeed: 0.02
|
pulseSpeed: 0.004, // Slower pulse
|
||||||
|
flowSpeed: 0.6, // Speed of flow animations
|
||||||
|
flowDensity: 0.001, // How often new flows start (lower = less frequent)
|
||||||
|
flowLength: 0.2 // Length of the flow (percentage of the connection)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
@@ -72,6 +88,9 @@ class NeuralNetworkBackground {
|
|||||||
document.addEventListener('darkModeToggled', (event) => {
|
document.addEventListener('darkModeToggled', (event) => {
|
||||||
this.isDarkMode = event.detail.isDark;
|
this.isDarkMode = event.detail.isDark;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Log that the background is initialized
|
||||||
|
console.log('Neural Network Background initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@@ -127,7 +146,7 @@ class NeuralNetworkBackground {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Fragment shader
|
// Fragment shader - Softer glow effect
|
||||||
const fsSource = `
|
const fsSource = `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
uniform vec4 uColor;
|
uniform vec4 uColor;
|
||||||
@@ -135,13 +154,9 @@ class NeuralNetworkBackground {
|
|||||||
void main() {
|
void main() {
|
||||||
float distance = length(gl_PointCoord - vec2(0.5, 0.5));
|
float distance = length(gl_PointCoord - vec2(0.5, 0.5));
|
||||||
|
|
||||||
// Soft circle with glow
|
// Softer glow with smoother falloff
|
||||||
float alpha = 1.0 - smoothstep(0.3, 0.5, distance);
|
float alpha = 1.0 - smoothstep(0.1, 0.5, distance);
|
||||||
|
alpha = pow(alpha, 1.5); // Make the glow even softer
|
||||||
// Add glow
|
|
||||||
if (distance > 0.3) {
|
|
||||||
alpha *= 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_FragColor = vec4(uColor.rgb, uColor.a * alpha);
|
gl_FragColor = vec4(uColor.rgb, uColor.a * alpha);
|
||||||
}
|
}
|
||||||
@@ -181,9 +196,7 @@ class NeuralNetworkBackground {
|
|||||||
this.sizeBuffer = this.gl.createBuffer();
|
this.sizeBuffer = this.gl.createBuffer();
|
||||||
|
|
||||||
// Set clear color for WebGL context
|
// Set clear color for WebGL context
|
||||||
const bgColor = this.isDarkMode
|
const bgColor = this.hexToRgb(this.darkModeColors.background);
|
||||||
? this.hexToRgb(this.darkModeColors.background)
|
|
||||||
: this.hexToRgb(this.lightModeColors.background);
|
|
||||||
|
|
||||||
this.gl.clearColor(bgColor.r/255, bgColor.g/255, bgColor.b/255, 1.0);
|
this.gl.clearColor(bgColor.r/255, bgColor.g/255, bgColor.b/255, 1.0);
|
||||||
}
|
}
|
||||||
@@ -228,6 +241,7 @@ class NeuralNetworkBackground {
|
|||||||
|
|
||||||
createConnections() {
|
createConnections() {
|
||||||
this.connections = [];
|
this.connections = [];
|
||||||
|
this.flows = []; // Reset flows
|
||||||
|
|
||||||
// Create connections between nearby nodes
|
// Create connections between nearby nodes
|
||||||
for (let i = 0; i < this.nodes.length; i++) {
|
for (let i = 0; i < this.nodes.length; i++) {
|
||||||
@@ -246,7 +260,8 @@ class NeuralNetworkBackground {
|
|||||||
from: i,
|
from: i,
|
||||||
to: j,
|
to: j,
|
||||||
distance: distance,
|
distance: distance,
|
||||||
opacity: Math.max(0, 1 - distance / this.config.connectionDistance) * this.config.connectionOpacity
|
opacity: Math.max(0, 1 - distance / this.config.connectionDistance) * this.config.connectionOpacity,
|
||||||
|
hasFlow: false // Each connection can have a flow
|
||||||
};
|
};
|
||||||
|
|
||||||
this.connections.push(connection);
|
this.connections.push(connection);
|
||||||
@@ -266,22 +281,34 @@ class NeuralNetworkBackground {
|
|||||||
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
||||||
const height = this.canvas.height / (window.devicePixelRatio || 1);
|
const height = this.canvas.height / (window.devicePixelRatio || 1);
|
||||||
|
|
||||||
// Update node positions
|
// Update node positions - slower, more flowing movement
|
||||||
for (let i = 0; i < this.nodes.length; i++) {
|
for (let i = 0; i < this.nodes.length; i++) {
|
||||||
const node = this.nodes[i];
|
const node = this.nodes[i];
|
||||||
|
|
||||||
|
// Move node with slight randomness for organic feel
|
||||||
|
node.speed.x += (Math.random() - 0.5) * 0.001;
|
||||||
|
node.speed.y += (Math.random() - 0.5) * 0.001;
|
||||||
|
|
||||||
|
// Dampen speeds for stability
|
||||||
|
node.speed.x *= 0.99;
|
||||||
|
node.speed.y *= 0.99;
|
||||||
|
|
||||||
|
// Apply speed limits
|
||||||
|
node.speed.x = Math.max(-this.config.animationSpeed, Math.min(this.config.animationSpeed, node.speed.x));
|
||||||
|
node.speed.y = Math.max(-this.config.animationSpeed, Math.min(this.config.animationSpeed, node.speed.y));
|
||||||
|
|
||||||
// Move node
|
// Move node
|
||||||
node.x += node.speed.x;
|
node.x += node.speed.x;
|
||||||
node.y += node.speed.y;
|
node.y += node.speed.y;
|
||||||
|
|
||||||
// Boundary check with bounce
|
// Boundary check with smooth bounce
|
||||||
if (node.x < 0 || node.x > width) {
|
if (node.x < 0 || node.x > width) {
|
||||||
node.speed.x *= -1;
|
node.speed.x *= -0.8; // Softer bounce
|
||||||
node.x = Math.max(0, Math.min(node.x, width));
|
node.x = Math.max(0, Math.min(node.x, width));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.y < 0 || node.y > height) {
|
if (node.y < 0 || node.y > height) {
|
||||||
node.speed.y *= -1;
|
node.speed.y *= -0.8; // Softer bounce
|
||||||
node.y = Math.max(0, Math.min(node.y, height));
|
node.y = Math.max(0, Math.min(node.y, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,8 +319,16 @@ class NeuralNetworkBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate connections dynamically
|
// Update flows
|
||||||
if (Math.random() < 0.05) { // Only recalculate 5% of the time for performance
|
this.updateFlows();
|
||||||
|
|
||||||
|
// Occasionally create new flows along connections
|
||||||
|
if (Math.random() < this.config.flowDensity) {
|
||||||
|
this.createNewFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate connections occasionally for a living network
|
||||||
|
if (Math.random() < 0.01) { // Only recalculate 1% of the time for performance
|
||||||
this.createConnections();
|
this.createConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,6 +343,52 @@ class NeuralNetworkBackground {
|
|||||||
this.animationFrameId = requestAnimationFrame(this.animate.bind(this));
|
this.animationFrameId = requestAnimationFrame(this.animate.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New method to update flow animations
|
||||||
|
updateFlows() {
|
||||||
|
// Update existing flows
|
||||||
|
for (let i = this.flows.length - 1; i >= 0; i--) {
|
||||||
|
const flow = this.flows[i];
|
||||||
|
flow.progress += this.config.flowSpeed / flow.connection.distance;
|
||||||
|
|
||||||
|
// Remove completed flows
|
||||||
|
if (flow.progress > 1.0) {
|
||||||
|
this.flows.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New method to create flow animations
|
||||||
|
createNewFlow() {
|
||||||
|
if (this.connections.length === 0) return;
|
||||||
|
|
||||||
|
// Select a random connection with preference for more connected nodes
|
||||||
|
let connectionIdx = Math.floor(Math.random() * this.connections.length);
|
||||||
|
let attempts = 0;
|
||||||
|
|
||||||
|
// Try to find a connection with more connected nodes
|
||||||
|
while (attempts < 5) {
|
||||||
|
const testIdx = Math.floor(Math.random() * this.connections.length);
|
||||||
|
const testConn = this.connections[testIdx];
|
||||||
|
const fromNode = this.nodes[testConn.from];
|
||||||
|
|
||||||
|
if (fromNode.connections.length > 2) {
|
||||||
|
connectionIdx = testIdx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = this.connections[connectionIdx];
|
||||||
|
|
||||||
|
// Create a new flow along this connection
|
||||||
|
this.flows.push({
|
||||||
|
connection: connection,
|
||||||
|
progress: 0,
|
||||||
|
direction: Math.random() > 0.5, // Randomly decide direction
|
||||||
|
length: this.config.flowLength + Math.random() * 0.1 // Slightly vary lengths
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
renderWebGL() {
|
renderWebGL() {
|
||||||
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
@@ -320,9 +401,12 @@ class NeuralNetworkBackground {
|
|||||||
// Set resolution uniform
|
// Set resolution uniform
|
||||||
this.gl.uniform2f(this.programInfo.uniformLocations.resolution, width, height);
|
this.gl.uniform2f(this.programInfo.uniformLocations.resolution, width, height);
|
||||||
|
|
||||||
// Draw connections
|
// Draw connections first (behind nodes)
|
||||||
this.renderConnectionsWebGL();
|
this.renderConnectionsWebGL();
|
||||||
|
|
||||||
|
// Draw flows on top of connections
|
||||||
|
this.renderFlowsWebGL();
|
||||||
|
|
||||||
// Draw nodes
|
// Draw nodes
|
||||||
this.renderNodesWebGL();
|
this.renderNodesWebGL();
|
||||||
}
|
}
|
||||||
@@ -337,9 +421,9 @@ class NeuralNetworkBackground {
|
|||||||
positions[i * 2] = node.x;
|
positions[i * 2] = node.x;
|
||||||
positions[i * 2 + 1] = node.y;
|
positions[i * 2 + 1] = node.y;
|
||||||
|
|
||||||
// Size with pulse effect
|
// Size with subtle pulse effect
|
||||||
const pulse = Math.sin(node.pulsePhase) * 0.3 + 1;
|
const pulse = Math.sin(node.pulsePhase) * 0.2 + 1;
|
||||||
sizes[i] = node.size * pulse * (node.connections.length > 3 ? 1.5 : 1);
|
sizes[i] = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind position buffer
|
// Bind position buffer
|
||||||
@@ -368,7 +452,7 @@ class NeuralNetworkBackground {
|
|||||||
);
|
);
|
||||||
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.pointSize);
|
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.pointSize);
|
||||||
|
|
||||||
// Set node color
|
// Set node color - more subtle
|
||||||
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
|
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
|
||||||
const nodeColor = this.hexToRgb(colorObj.nodeColor);
|
const nodeColor = this.hexToRgb(colorObj.nodeColor);
|
||||||
this.gl.uniform4f(
|
this.gl.uniform4f(
|
||||||
@@ -376,12 +460,12 @@ class NeuralNetworkBackground {
|
|||||||
nodeColor.r / 255,
|
nodeColor.r / 255,
|
||||||
nodeColor.g / 255,
|
nodeColor.g / 255,
|
||||||
nodeColor.b / 255,
|
nodeColor.b / 255,
|
||||||
0.8 // Alpha
|
0.7 // Lower opacity for subtlety
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw nodes
|
// Draw nodes
|
||||||
this.gl.enable(this.gl.BLEND);
|
this.gl.enable(this.gl.BLEND);
|
||||||
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE); // Additive blending for glow
|
||||||
this.gl.drawArrays(this.gl.POINTS, 0, this.nodes.length);
|
this.gl.drawArrays(this.gl.POINTS, 0, this.nodes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +497,7 @@ class NeuralNetworkBackground {
|
|||||||
// Disable point size attribute for lines
|
// Disable point size attribute for lines
|
||||||
this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize);
|
this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize);
|
||||||
|
|
||||||
// Set line color with connection opacity
|
// Set line color with connection opacity - darker, more subtle
|
||||||
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
|
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
|
||||||
const lineColor = this.hexToRgb(colorObj.connectionColor);
|
const lineColor = this.hexToRgb(colorObj.connectionColor);
|
||||||
this.gl.uniform4f(
|
this.gl.uniform4f(
|
||||||
@@ -421,22 +505,9 @@ class NeuralNetworkBackground {
|
|||||||
lineColor.r / 255,
|
lineColor.r / 255,
|
||||||
lineColor.g / 255,
|
lineColor.g / 255,
|
||||||
lineColor.b / 255,
|
lineColor.b / 255,
|
||||||
connection.opacity
|
connection.opacity * 0.8 // Reduced for subtlety
|
||||||
);
|
);
|
||||||
|
|
||||||
// Data pulse animation along connection
|
|
||||||
if (Math.random() < 0.01 && fromNode.connections.length > 2) {
|
|
||||||
// Draw data pulse (slightly different color)
|
|
||||||
const pulseColor = this.hexToRgb(colorObj.nodePulse);
|
|
||||||
this.gl.uniform4f(
|
|
||||||
this.programInfo.uniformLocations.color,
|
|
||||||
pulseColor.r / 255,
|
|
||||||
pulseColor.g / 255,
|
|
||||||
pulseColor.b / 255,
|
|
||||||
0.8
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the line
|
// Draw the line
|
||||||
this.gl.enable(this.gl.BLEND);
|
this.gl.enable(this.gl.BLEND);
|
||||||
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
|
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
|
||||||
@@ -445,6 +516,94 @@ class NeuralNetworkBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New method to render the flowing animations
|
||||||
|
renderFlowsWebGL() {
|
||||||
|
// For each flow, draw a segment along its connection
|
||||||
|
for (const flow of this.flows) {
|
||||||
|
const connection = flow.connection;
|
||||||
|
const fromNode = this.nodes[connection.from];
|
||||||
|
const toNode = this.nodes[connection.to];
|
||||||
|
|
||||||
|
// Calculate flow position
|
||||||
|
const startProgress = flow.progress;
|
||||||
|
const endProgress = Math.min(1, startProgress + flow.length);
|
||||||
|
|
||||||
|
// If flow hasn't started yet or has finished
|
||||||
|
if (startProgress >= 1 || endProgress <= 0) continue;
|
||||||
|
|
||||||
|
// Calculate actual positions
|
||||||
|
const direction = flow.direction ? 1 : -1;
|
||||||
|
let p1, p2;
|
||||||
|
|
||||||
|
if (direction > 0) {
|
||||||
|
p1 = {
|
||||||
|
x: fromNode.x + (toNode.x - fromNode.x) * startProgress,
|
||||||
|
y: fromNode.y + (toNode.y - fromNode.y) * startProgress
|
||||||
|
};
|
||||||
|
p2 = {
|
||||||
|
x: fromNode.x + (toNode.x - fromNode.x) * endProgress,
|
||||||
|
y: fromNode.y + (toNode.y - fromNode.y) * endProgress
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
p1 = {
|
||||||
|
x: toNode.x + (fromNode.x - toNode.x) * startProgress,
|
||||||
|
y: toNode.y + (fromNode.y - toNode.y) * startProgress
|
||||||
|
};
|
||||||
|
p2 = {
|
||||||
|
x: toNode.x + (fromNode.x - toNode.x) * endProgress,
|
||||||
|
y: toNode.y + (fromNode.y - toNode.y) * endProgress
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line positions for the flow
|
||||||
|
const positions = new Float32Array([
|
||||||
|
p1.x, p1.y,
|
||||||
|
p2.x, p2.y
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Bind position buffer
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||||
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW);
|
||||||
|
this.gl.vertexAttribPointer(
|
||||||
|
this.programInfo.attribLocations.vertexPosition,
|
||||||
|
2, // components per vertex
|
||||||
|
this.gl.FLOAT, // data type
|
||||||
|
false, // normalize
|
||||||
|
0, // stride
|
||||||
|
0 // offset
|
||||||
|
);
|
||||||
|
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition);
|
||||||
|
|
||||||
|
// Disable point size attribute for lines
|
||||||
|
this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize);
|
||||||
|
|
||||||
|
// Fade the flow at the beginning and end
|
||||||
|
const fadeEdge = 0.2;
|
||||||
|
const fadeOpacity = Math.min(
|
||||||
|
startProgress / fadeEdge,
|
||||||
|
(1 - endProgress) / fadeEdge,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Flow color - subtle glow
|
||||||
|
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
|
||||||
|
const flowColor = this.hexToRgb(colorObj.flowColor);
|
||||||
|
this.gl.uniform4f(
|
||||||
|
this.programInfo.uniformLocations.color,
|
||||||
|
flowColor.r / 255,
|
||||||
|
flowColor.g / 255,
|
||||||
|
flowColor.b / 255,
|
||||||
|
0.4 * fadeOpacity // Subtle flow opacity
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw the flow line
|
||||||
|
this.gl.enable(this.gl.BLEND);
|
||||||
|
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
|
||||||
|
this.gl.lineWidth(1.5); // Slightly thicker for visibility
|
||||||
|
this.gl.drawArrays(this.gl.LINES, 0, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
renderCanvas() {
|
renderCanvas() {
|
||||||
// Clear canvas
|
// Clear canvas
|
||||||
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
||||||
@@ -478,6 +637,9 @@ class NeuralNetworkBackground {
|
|||||||
this.ctx.stroke();
|
this.ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw flows
|
||||||
|
this.renderFlowsCanvas();
|
||||||
|
|
||||||
// Draw nodes
|
// Draw nodes
|
||||||
const nodeColor = this.isDarkMode
|
const nodeColor = this.isDarkMode
|
||||||
? this.darkModeColors.nodeColor
|
? this.darkModeColors.nodeColor
|
||||||
@@ -488,9 +650,9 @@ class NeuralNetworkBackground {
|
|||||||
: this.lightModeColors.nodePulse;
|
: this.lightModeColors.nodePulse;
|
||||||
|
|
||||||
for (const node of this.nodes) {
|
for (const node of this.nodes) {
|
||||||
// Node with glow effect
|
// Node with subtle glow effect
|
||||||
const pulse = Math.sin(node.pulsePhase) * 0.3 + 1;
|
const pulse = Math.sin(node.pulsePhase) * 0.2 + 1;
|
||||||
const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.5 : 1);
|
const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1);
|
||||||
|
|
||||||
// Glow effect
|
// Glow effect
|
||||||
const glow = this.ctx.createRadialGradient(
|
const glow = this.ctx.createRadialGradient(
|
||||||
@@ -501,7 +663,7 @@ class NeuralNetworkBackground {
|
|||||||
const rgbNodeColor = this.hexToRgb(nodeColor);
|
const rgbNodeColor = this.hexToRgb(nodeColor);
|
||||||
const rgbPulseColor = this.hexToRgb(nodePulse);
|
const rgbPulseColor = this.hexToRgb(nodePulse);
|
||||||
|
|
||||||
glow.addColorStop(0, `rgba(${rgbPulseColor.r}, ${rgbPulseColor.g}, ${rgbPulseColor.b}, 0.8)`);
|
glow.addColorStop(0, `rgba(${rgbPulseColor.r}, ${rgbPulseColor.g}, ${rgbPulseColor.b}, 0.6)`);
|
||||||
glow.addColorStop(0.5, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0.2)`);
|
glow.addColorStop(0.5, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0.2)`);
|
||||||
glow.addColorStop(1, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0)`);
|
glow.addColorStop(1, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0)`);
|
||||||
|
|
||||||
@@ -518,18 +680,89 @@ class NeuralNetworkBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New method to render flows in Canvas mode
|
||||||
|
renderFlowsCanvas() {
|
||||||
|
if (!this.ctx) return;
|
||||||
|
|
||||||
|
const flowColor = this.isDarkMode
|
||||||
|
? this.darkModeColors.flowColor
|
||||||
|
: this.lightModeColors.flowColor;
|
||||||
|
|
||||||
|
const rgbFlowColor = this.hexToRgb(flowColor);
|
||||||
|
|
||||||
|
for (const flow of this.flows) {
|
||||||
|
const connection = flow.connection;
|
||||||
|
const fromNode = this.nodes[connection.from];
|
||||||
|
const toNode = this.nodes[connection.to];
|
||||||
|
|
||||||
|
// Calculate flow position
|
||||||
|
const startProgress = flow.progress;
|
||||||
|
const endProgress = Math.min(1, startProgress + flow.length);
|
||||||
|
|
||||||
|
// If flow hasn't started yet or has finished
|
||||||
|
if (startProgress >= 1 || endProgress <= 0) continue;
|
||||||
|
|
||||||
|
// Calculate actual positions
|
||||||
|
const direction = flow.direction ? 1 : -1;
|
||||||
|
let p1, p2;
|
||||||
|
|
||||||
|
if (direction > 0) {
|
||||||
|
p1 = {
|
||||||
|
x: fromNode.x + (toNode.x - fromNode.x) * startProgress,
|
||||||
|
y: fromNode.y + (toNode.y - fromNode.y) * startProgress
|
||||||
|
};
|
||||||
|
p2 = {
|
||||||
|
x: fromNode.x + (toNode.x - fromNode.x) * endProgress,
|
||||||
|
y: fromNode.y + (toNode.y - fromNode.y) * endProgress
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
p1 = {
|
||||||
|
x: toNode.x + (fromNode.x - toNode.x) * startProgress,
|
||||||
|
y: toNode.y + (fromNode.y - toNode.y) * startProgress
|
||||||
|
};
|
||||||
|
p2 = {
|
||||||
|
x: toNode.x + (fromNode.x - toNode.x) * endProgress,
|
||||||
|
y: toNode.y + (fromNode.y - toNode.y) * endProgress
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade the flow at the beginning and end
|
||||||
|
const fadeEdge = 0.2;
|
||||||
|
const fadeOpacity = Math.min(
|
||||||
|
startProgress / fadeEdge,
|
||||||
|
(1 - endProgress) / fadeEdge,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw flow
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(p1.x, p1.y);
|
||||||
|
this.ctx.lineTo(p2.x, p2.y);
|
||||||
|
this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.4 * fadeOpacity})`;
|
||||||
|
this.ctx.lineWidth = 1.5;
|
||||||
|
this.ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper method to convert hex to RGB
|
// Helper method to convert hex to RGB
|
||||||
hexToRgb(hex) {
|
hexToRgb(hex) {
|
||||||
// Remove # if present
|
// Remove # if present
|
||||||
hex = hex.replace(/^#/, '');
|
hex = hex.replace(/^#/, '');
|
||||||
|
|
||||||
|
// Handle rgba hex format
|
||||||
|
let alpha = 1;
|
||||||
|
if (hex.length === 8) {
|
||||||
|
alpha = parseInt(hex.slice(6, 8), 16) / 255;
|
||||||
|
hex = hex.slice(0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
// Parse hex values
|
// Parse hex values
|
||||||
const bigint = parseInt(hex, 16);
|
const bigint = parseInt(hex, 16);
|
||||||
const r = (bigint >> 16) & 255;
|
const r = (bigint >> 16) & 255;
|
||||||
const g = (bigint >> 8) & 255;
|
const g = (bigint >> 8) & 255;
|
||||||
const b = bigint & 255;
|
const b = bigint & 255;
|
||||||
|
|
||||||
return { r, g, b };
|
return { r, g, b, a: alpha };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup method
|
// Cleanup method
|
||||||
@@ -555,7 +788,21 @@ class NeuralNetworkBackground {
|
|||||||
|
|
||||||
// Initialize when DOM is loaded
|
// Initialize when DOM is loaded
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Short delay to ensure DOM is fully loaded
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!window.neuralNetworkBackground) {
|
||||||
|
console.log('Creating Neural Network Background');
|
||||||
window.neuralNetworkBackground = new NeuralNetworkBackground();
|
window.neuralNetworkBackground = new NeuralNetworkBackground();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-initialize when page is fully loaded (for safety)
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
if (!window.neuralNetworkBackground) {
|
||||||
|
console.log('Re-initializing Neural Network Background on full load');
|
||||||
|
window.neuralNetworkBackground = new NeuralNetworkBackground();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clean up when window is closed
|
// Clean up when window is closed
|
||||||
|
|||||||
@@ -43,16 +43,24 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
transition: background-color var(--transition-normal), color var(--transition-normal);
|
transition: background-color var(--transition-normal), color var(--transition-normal);
|
||||||
|
background-color: transparent !important; /* Ensure background is transparent */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Theme Specific */
|
/* HTML root element should also be transparent */
|
||||||
|
html {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Theme Specific - keep the color but remove background */
|
||||||
body {
|
body {
|
||||||
background-color: var(--light-bg-primary);
|
|
||||||
color: var(--light-text-primary);
|
color: var(--light-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.dark {
|
body.dark {
|
||||||
background-color: var(--dark-bg-primary);
|
|
||||||
color: var(--dark-text-primary);
|
color: var(--dark-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,9 @@
|
|||||||
<!-- Alpine.js -->
|
<!-- Alpine.js -->
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js"></script>
|
||||||
|
|
||||||
|
<!-- Neural Network Background CSS -->
|
||||||
|
<link href="{{ url_for('static', filename='css/neural-network-background.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Neural Network Background Script -->
|
<!-- Neural Network Background Script -->
|
||||||
<script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
|
<script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user