diff --git a/ChatGPT Image 20. Apr. 2025, 09_02_47.png b/ChatGPT Image 20. Apr. 2025, 09_02_47.png new file mode 100644 index 0000000..c87515b Binary files /dev/null and b/ChatGPT Image 20. Apr. 2025, 09_02_47.png differ diff --git a/website/static/css/neural-network-background.css b/website/static/css/neural-network-background.css new file mode 100644 index 0000000..593add5 --- /dev/null +++ b/website/static/css/neural-network-background.css @@ -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; +} \ No newline at end of file diff --git a/website/static/neural-network-background.js b/website/static/neural-network-background.js index a8abd2e..103b43e 100644 --- a/website/static/neural-network-background.js +++ b/website/static/neural-network-background.js @@ -1,6 +1,7 @@ /** * Neural Network Background Animation * Modern, darker, mystical theme using WebGL + * Subtle flowing network aesthetic */ class NeuralNetworkBackground { @@ -13,11 +14,22 @@ class NeuralNetworkBackground { this.canvas.style.left = '0'; this.canvas.style.width = '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.opacity = '1'; // Force visibility - // Append to body - document.body.appendChild(this.canvas); + // 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); + } // WebGL context this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl'); @@ -33,16 +45,17 @@ class NeuralNetworkBackground { // Animation properties this.nodes = []; this.connections = []; + this.flows = []; // Flow animations along connections 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 = { - background: '#0a0e19', - nodeColor: '#6d28d9', - nodePulse: '#8b5cf6', - connectionColor: '#4c1d95', - glowColor: '#7c3aed' + background: '#050a14', // Darker blue-black background + nodeColor: '#4a5568', // Darker nodes for subtlety + nodePulse: '#718096', // Subtle blue pulse + connectionColor: '#2d3748', // Darker connections + flowColor: '#4a88ff80' // Semi-transparent flow highlight }; this.lightModeColors = { @@ -50,18 +63,21 @@ class NeuralNetworkBackground { nodeColor: '#7c3aed', nodePulse: '#8b5cf6', connectionColor: '#a78bfa', - glowColor: '#c4b5fd' + flowColor: '#c4b5fd' }; - // Config + // Config - Updated to be more flowing and subtle this.config = { - nodeCount: 100, - nodeSize: 2, - nodeVariation: 1.5, - connectionDistance: 150, - connectionOpacity: 0.2, - animationSpeed: 0.3, - pulseSpeed: 0.02 + nodeCount: 100, // Slightly fewer nodes for cleaner look + nodeSize: 0.8, // Smaller nodes + nodeVariation: 0.5, // Less variation for uniformity + connectionDistance: 200, // Longer connections for better flow + connectionOpacity: 0.2, // More subtle connections + animationSpeed: 0.08, // Much slower movement + 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 @@ -72,6 +88,9 @@ class NeuralNetworkBackground { document.addEventListener('darkModeToggled', (event) => { this.isDarkMode = event.detail.isDark; }); + + // Log that the background is initialized + console.log('Neural Network Background initialized'); } init() { @@ -127,7 +146,7 @@ class NeuralNetworkBackground { } `; - // Fragment shader + // Fragment shader - Softer glow effect const fsSource = ` precision mediump float; uniform vec4 uColor; @@ -135,13 +154,9 @@ class NeuralNetworkBackground { void main() { float distance = length(gl_PointCoord - vec2(0.5, 0.5)); - // Soft circle with glow - float alpha = 1.0 - smoothstep(0.3, 0.5, distance); - - // Add glow - if (distance > 0.3) { - alpha *= 0.7; - } + // Softer glow with smoother falloff + float alpha = 1.0 - smoothstep(0.1, 0.5, distance); + alpha = pow(alpha, 1.5); // Make the glow even softer gl_FragColor = vec4(uColor.rgb, uColor.a * alpha); } @@ -181,9 +196,7 @@ class NeuralNetworkBackground { this.sizeBuffer = this.gl.createBuffer(); // Set clear color for WebGL context - const bgColor = this.isDarkMode - ? this.hexToRgb(this.darkModeColors.background) - : this.hexToRgb(this.lightModeColors.background); + const bgColor = this.hexToRgb(this.darkModeColors.background); this.gl.clearColor(bgColor.r/255, bgColor.g/255, bgColor.b/255, 1.0); } @@ -195,7 +208,7 @@ class NeuralNetworkBackground { if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { console.error('An error occurred compiling the shaders: ' + - this.gl.getShaderInfoLog(shader)); + this.gl.getShaderInfoLog(shader)); this.gl.deleteShader(shader); return null; } @@ -228,6 +241,7 @@ class NeuralNetworkBackground { createConnections() { this.connections = []; + this.flows = []; // Reset flows // Create connections between nearby nodes for (let i = 0; i < this.nodes.length; i++) { @@ -246,7 +260,8 @@ class NeuralNetworkBackground { from: i, to: j, 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); @@ -266,22 +281,34 @@ class NeuralNetworkBackground { const width = this.canvas.width / (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++) { 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 node.x += node.speed.x; node.y += node.speed.y; - // Boundary check with bounce + // Boundary check with smooth bounce 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)); } 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)); } @@ -292,8 +319,16 @@ class NeuralNetworkBackground { } } - // Recalculate connections dynamically - if (Math.random() < 0.05) { // Only recalculate 5% of the time for performance + // Update flows + 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(); } @@ -308,6 +343,52 @@ class NeuralNetworkBackground { 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() { this.gl.clear(this.gl.COLOR_BUFFER_BIT); @@ -320,9 +401,12 @@ class NeuralNetworkBackground { // Set resolution uniform this.gl.uniform2f(this.programInfo.uniformLocations.resolution, width, height); - // Draw connections + // Draw connections first (behind nodes) this.renderConnectionsWebGL(); + // Draw flows on top of connections + this.renderFlowsWebGL(); + // Draw nodes this.renderNodesWebGL(); } @@ -337,9 +421,9 @@ class NeuralNetworkBackground { positions[i * 2] = node.x; positions[i * 2 + 1] = node.y; - // Size with pulse effect - const pulse = Math.sin(node.pulsePhase) * 0.3 + 1; - sizes[i] = node.size * pulse * (node.connections.length > 3 ? 1.5 : 1); + // Size with subtle pulse effect + const pulse = Math.sin(node.pulsePhase) * 0.2 + 1; + sizes[i] = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1); } // Bind position buffer @@ -368,7 +452,7 @@ class NeuralNetworkBackground { ); this.gl.enableVertexAttribArray(this.programInfo.attribLocations.pointSize); - // Set node color + // Set node color - more subtle const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors; const nodeColor = this.hexToRgb(colorObj.nodeColor); this.gl.uniform4f( @@ -376,12 +460,12 @@ class NeuralNetworkBackground { nodeColor.r / 255, nodeColor.g / 255, nodeColor.b / 255, - 0.8 // Alpha + 0.7 // Lower opacity for subtlety ); // Draw nodes 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); } @@ -413,7 +497,7 @@ class NeuralNetworkBackground { // Disable point size attribute for lines 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 lineColor = this.hexToRgb(colorObj.connectionColor); this.gl.uniform4f( @@ -421,22 +505,9 @@ class NeuralNetworkBackground { lineColor.r / 255, lineColor.g / 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 this.gl.enable(this.gl.BLEND); 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() { // Clear canvas const width = this.canvas.width / (window.devicePixelRatio || 1); @@ -478,6 +637,9 @@ class NeuralNetworkBackground { this.ctx.stroke(); } + // Draw flows + this.renderFlowsCanvas(); + // Draw nodes const nodeColor = this.isDarkMode ? this.darkModeColors.nodeColor @@ -488,9 +650,9 @@ class NeuralNetworkBackground { : this.lightModeColors.nodePulse; for (const node of this.nodes) { - // Node with glow effect - const pulse = Math.sin(node.pulsePhase) * 0.3 + 1; - const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.5 : 1); + // Node with subtle glow effect + const pulse = Math.sin(node.pulsePhase) * 0.2 + 1; + const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1); // Glow effect const glow = this.ctx.createRadialGradient( @@ -501,7 +663,7 @@ class NeuralNetworkBackground { const rgbNodeColor = this.hexToRgb(nodeColor); 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(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 hexToRgb(hex) { // Remove # if present 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 const bigint = parseInt(hex, 16); const r = (bigint >> 16) & 255; const g = (bigint >> 8) & 255; const b = bigint & 255; - return { r, g, b }; + return { r, g, b, a: alpha }; } // Cleanup method @@ -555,7 +788,21 @@ class NeuralNetworkBackground { // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', () => { - window.neuralNetworkBackground = new NeuralNetworkBackground(); + // Short delay to ensure DOM is fully loaded + setTimeout(() => { + if (!window.neuralNetworkBackground) { + console.log('Creating Neural Network Background'); + 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 diff --git a/website/static/style.css b/website/static/style.css index c387931..9e05d85 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -43,16 +43,24 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; 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 { - background-color: var(--light-bg-primary); color: var(--light-text-primary); } body.dark { - background-color: var(--dark-bg-primary); color: var(--dark-text-primary); } diff --git a/website/templates/base.html b/website/templates/base.html index 35664a3..35f218a 100644 --- a/website/templates/base.html +++ b/website/templates/base.html @@ -83,6 +83,9 @@ + + +