Skip to content

Default controller theme exploration #1529

@clicksave

Description

@clicksave

OK explore something a little more unique for the default controller theme. Alex has vibe coded some animations, and we should explore possibly implementing something like this.

Heres a video

Dynamic.Theme.Behavior.mov

Some high level questions I have. Is this too computationally intensive? is there a light weight way we could replace the default controller theme with something like this?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Diamond Stars Header</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: #000000;
      font-family: Arial, sans-serif;
    }
    
    .header-container {
      width: 400px;
      height: 120px;
      background-color: #181818;
      border-radius: 10px;
      overflow: hidden;
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
      position: relative;
    }
    
    .gradient-fade {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 40px;
      background: linear-gradient(to bottom, transparent, #181818);
      z-index: 5;
    }
    
    .star {
      position: absolute;
      background-color: #FFD700;
      transform: rotate(45deg);
    }
    
    .star.foreground {
      box-shadow: 0 0 6px rgba(255, 215, 0, 0.7);
    }
    
    .star.middle {
      box-shadow: 0 0 4px rgba(255, 215, 0, 0.5);
    }
    
    .star.background {
      box-shadow: 0 0 2px rgba(255, 215, 0, 0.3);
    }
  </style>
</head>
<body>
  <div class="header-container" id="header-container">
    <div id="starfield"></div>
    <div class="gradient-fade"></div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // Fixed dimensions - these won't change
      const HEADER_WIDTH = 400;
      const HEADER_HEIGHT = 120;
      
      const container = document.getElementById('header-container');
      const starfield = document.getElementById('starfield');
      
      // Star settings
      const starCount = 120;
      const stars = [];
      
      // Mouse tracking
      let mouseX = window.innerWidth / 2;
      let mouseY = window.innerHeight / 2;
      let containerRect = container.getBoundingClientRect();
      
      document.addEventListener('mousemove', function(e) {
        mouseX = e.clientX;
        mouseY = e.clientY;
      });
      
      // Create all stars and add them to the DOM
      function createStars() {
        // Layer distribution
        const foregroundCount = Math.round(starCount * 0.15);
        const middleCount = Math.round(starCount * 0.25);
        const backgroundCount = starCount - foregroundCount - middleCount;
        
        // Create foreground stars (15%)
        for (let i = 0; i < foregroundCount; i++) {
          createStarInLayer('foreground', 2.0, 3.5, 0.7, 1.0, 0.4);
        }
        
        // Create middle stars (25%)
        for (let i = 0; i < middleCount; i++) {
          createStarInLayer('middle', 1.2, 2.2, 0.5, 0.8, 0.25);
        }
        
        // Create background stars (60%)
        for (let i = 0; i < backgroundCount; i++) {
          createStarInLayer('background', 0.5, 1.3, 0.3, 0.5, 0.12);
        }
      }
      
      // Helper to create a star in a specific layer
      function createStarInLayer(layerClass, minSize, maxSize, minOpacity, maxOpacity, maxSpeed) {
        // Generate random size and opacity
        const size = minSize + Math.random() * (maxSize - minSize);
        const opacity = minOpacity + Math.random() * (maxOpacity - minOpacity);
        const speed = 0.1 + Math.random() * maxSpeed;
        
        // Create the DOM element
        const element = document.createElement('div');
        element.className = `star ${layerClass}`;
        element.style.width = `${size}px`;
        element.style.height = `${size}px`;
        element.style.opacity = opacity;
        
        // Position the star randomly within the header bounds
        const xPos = Math.random() * HEADER_WIDTH;
        const yPos = Math.random() * HEADER_HEIGHT;
        element.style.left = `${xPos}px`;
        element.style.top = `${yPos}px`;
        
        starfield.appendChild(element);
        
        // Add to the stars array
        stars.push({
          element,
          x: xPos,
          y: yPos,
          size,
          speed,
          layer: layerClass,
          dx: 0,
          dy: 0
        });
      }
      
      // Animation loop
      function animate() {
        // Get the center of the header
        const headerCenterX = containerRect.left + HEADER_WIDTH / 2;
        const headerCenterY = containerRect.top + HEADER_HEIGHT / 2;
        
        // Calculate the vector from center to mouse
        const dx = mouseX - headerCenterX;
        const dy = mouseY - headerCenterY;
        const dist = Math.sqrt(dx * dx + dy * dy);
        
        // Calculate influence based on distance
        const maxDist = Math.max(window.innerWidth, window.innerHeight) / 3;
        let influence = Math.max(0, 1 - dist / maxDist);
        influence = Math.pow(influence, 0.5);
        
        // Target movement direction
        const targetX = (dist > 0.1) ? (dx / dist) * influence : 0;
        const targetY = (dist > 0.1) ? (dy / dist) * influence * 0.5 : 0;
        
        // Update each star
        stars.forEach(star => {
          // Different easing based on layer
          const ease = (star.layer === 'foreground') ? 0.04 : 
                      (star.layer === 'middle') ? 0.02 : 0.01;
          
          // Ease toward target direction
          star.dx += (targetX - star.dx) * ease;
          star.dy += (targetY - star.dy) * ease;
          
          // Apply movement
          star.x += star.dx * star.speed;
          star.y += star.dy * star.speed;
          
          // Wrap around edges
          if (star.x < -5) star.x = HEADER_WIDTH + 5;
          else if (star.x > HEADER_WIDTH + 5) star.x = -5;
          
          if (star.y < -5) star.y = HEADER_HEIGHT + 5;
          else if (star.y > HEADER_HEIGHT + 5) star.y = -5;
          
          // Update DOM element position
          star.element.style.left = `${star.x}px`;
          star.element.style.top = `${star.y}px`;
        });
        
        // Continue animation
        requestAnimationFrame(animate);
      }
      
      // Initialize everything
      function init() {
        createStars();
        containerRect = container.getBoundingClientRect();
        requestAnimationFrame(animate);
      }
      
      // Update container position on resize
      window.addEventListener('resize', function() {
        containerRect = container.getBoundingClientRect();
      });
      
      // Start everything
      init();
    });
  </script>
</body>
</html>

It may turn out that this is too computationally intensive, maybe not, lets explore what it would mean to implement it. If that turns out to be the case, are there improvements we could make to the animation?

Let me know how it goes!

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions