@manufosela/constellation-sky

@manufosela/constellation-sky

A Lit 3 web component for animated star constellations with connecting lines using Canvas API

Constellation Sky

Interactive animated star constellations for the web

Move your mouse to interact with the stars

Scroll down for more demos

Theme Variations

Different background themes using CSS custom properties

Ocean Theme

Warm Theme

Forest Theme

Sunset Theme

Live Configuration

Adjust all parameters in real-time

Density Comparison

Different star counts and line distances

Sparse (30 stars)

Dense (150 stars)

Stars Only Mode

No connecting lines - pure starfield

Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<!-- Hero Section -->
  <section class="hero">
    <constellation-sky
      id="hero-sky"
      star-count="120"
      line-distance="150"
      speed="0.2"
      interactive
    ></constellation-sky>
    <div class="hero-content">
      <h1>Constellation Sky</h1>
      <p>Interactive animated star constellations for the web</p>
      <p style="color: #666; font-size: 0.9rem;">Move your mouse to interact with the stars</p>
    </div>
    <div class="scroll-hint">Scroll down for more demos</div>
  </section>

  <!-- Demo Sections -->
  <div class="demo-sections">
    <!-- Theme Variations -->
    <section class="demo-section">
      <h2>Theme Variations</h2>
      <p>Different background themes using CSS custom properties</p>

      <div class="demo-grid">
        <div class="demo-card">
          <h3>Ocean Theme</h3>
          <constellation-sky
            class="theme-ocean"
            star-count="60"
            star-color="#87ceeb"
            line-color="#4da6ff"
            line-distance="100"
          ></constellation-sky>
        </div>

        <div class="demo-card">
          <h3>Warm Theme</h3>
          <constellation-sky
            class="theme-warm"
            star-count="70"
            star-color="#ffcc66"
            line-color="#ff9933"
            line-distance="90"
          ></constellation-sky>
        </div>

        <div class="demo-card">
          <h3>Forest Theme</h3>
          <constellation-sky
            class="theme-forest"
            star-count="50"
            star-color="#90ee90"
            line-color="#32cd32"
            line-distance="80"
          ></constellation-sky>
        </div>

        <div class="demo-card">
          <h3>Sunset Theme</h3>
          <constellation-sky
            class="theme-sunset"
            star-count="80"
            star-color="#ff69b4"
            line-color="#ff1493"
            line-distance="110"
          ></constellation-sky>
        </div>
      </div>
    </section>

    <!-- Configuration Demo -->
    <section class="demo-section">
      <h2>Live Configuration</h2>
      <p>Adjust all parameters in real-time</p>

      <div class="demo-card" style="max-width: 800px; margin: 0 auto;">
        <constellation-sky
          id="configurable"
          star-count="80"
          line-distance="120"
          speed="0.3"
          interactive
        ></constellation-sky>
        <div class="controls-panel">
          <div class="control-group">
            <label>Stars: <span id="star-value">80</span></label>
            <input type="range" id="star-range" min="20" max="200" value="80">
          </div>
          <div class="control-group">
            <label>Line Distance: <span id="line-value">120</span></label>
            <input type="range" id="line-range" min="50" max="250" value="120">
          </div>
          <div class="control-group">
            <label>Speed: <span id="speed-value">0.3</span></label>
            <input type="range" id="speed-range" min="0" max="1" step="0.1" value="0.3">
          </div>
          <div class="control-group">
            <label>Star Color</label>
            <input type="color" id="star-color" value="#ffffff">
          </div>
          <div class="control-group">
            <label>Line Color</label>
            <input type="color" id="line-color" value="#ffffff">
          </div>
          <button id="toggle-lines">Toggle Lines</button>
          <button id="toggle-pause">Pause</button>
          <button id="reset-btn">Reset</button>
        </div>
      </div>
    </section>

    <!-- Dense vs Sparse -->
    <section class="demo-section">
      <h2>Density Comparison</h2>
      <p>Different star counts and line distances</p>

      <div class="demo-grid">
        <div class="demo-card">
          <h3>Sparse (30 stars)</h3>
          <constellation-sky
            star-count="30"
            line-distance="200"
            speed="0.2"
          ></constellation-sky>
        </div>

        <div class="demo-card">
          <h3>Dense (150 stars)</h3>
          <constellation-sky
            star-count="150"
            line-distance="80"
            speed="0.4"
          ></constellation-sky>
        </div>
      </div>
    </section>

    <!-- Stars Only -->
    <section class="demo-section">
      <h2>Stars Only Mode</h2>
      <p>No connecting lines - pure starfield</p>

      <div class="demo-card" style="max-width: 800px; margin: 0 auto;">
        <constellation-sky
          star-count="200"
          speed="0.1"
          show-lines="false"
          interactive="false"
          style="--constellation-height: 400px;"
        ></constellation-sky>
      </div>
    </section>
  </div>
CSS (css)
:root {
  --bg: #0c0f14;
  --bg-elevated: #141923;
  --bg-panel: #171d28;
  --border: #262f3f;
  --text: #f4f6fb;
  --text-muted: #a7b0c2;
  --text-dim: #7d879b;
  --accent: #ff8a3d;
  --accent-strong: #ff6a00;
  --accent-soft: rgba(255, 138, 61, 0.16);
  --shadow: 0 20px 50px rgba(5, 8, 14, 0.45);
  --radius-lg: 22px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --max-width: 1160px;
}

* {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    h1, h2 {
      text-align: center;
    }

    .hero {
      position: relative;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }

    .hero constellation-sky {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }

    .hero-content {
      position: relative;
      z-index: 2;
      text-align: center;
      padding: 20px;
    }

    .hero h1 {
      font-size: 3rem;
      margin-bottom: 1rem;
      text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
    }

    .hero p {
      font-size: 1.2rem;
      color: var(--text-muted);
      margin-bottom: 2rem;
    }

    .demo-sections {
      padding: 40px 20px;
      max-width: 1400px;
      margin: 0 auto;
    }

    .demo-section {
      margin-bottom: 60px;
    }

    .demo-section h2 {
      margin-bottom: 10px;
      color: #4ecdc4;
    }

    .demo-section p {
      text-align: center;
      color: #888;
      margin-bottom: 20px;
    }

    .demo-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
      gap: 30px;
    }

    .demo-card {
      background: rgba(255, 255, 255, 0.03);
      border-radius: 16px;
      overflow: hidden;
      border: 1px solid rgba(255, 255, 255, 0.1);
    }

    .demo-card h3 {
      padding: 15px 20px;
      background: rgba(255, 255, 255, 0.05);
      margin: 0;
      font-size: 1rem;
    }

    .demo-card constellation-sky {
      display: block;
      height: 300px;
    }

    .controls-panel {
      padding: 20px;
      background: rgba(0, 0, 0, 0.3);
      display: flex;
      flex-wrap: wrap;
      gap: 15px;
      align-items: center;
      justify-content: center;
    }

    .control-group {
      display: flex;
      flex-direction: column;
      gap: 5px;
    }

    .control-group label {
      font-size: 0.8rem;
      color: #888;
    }

    .control-group input[type="range"] {
      width: 120px;
    }

    .control-group input[type="color"] {
      width: 60px;
      height: 30px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    button {
      padding: 10px 20px;
      background: rgba(78, 205, 196, 0.2);
      border: 1px solid #4ecdc4;
      color: #4ecdc4;
      border-radius: 6px;
      cursor: pointer;
      font-size: 0.9rem;
      transition: all 0.2s;
    }

    button:hover {
      background: rgba(78, 205, 196, 0.3);
    }

    button.active {
      background: #4ecdc4;
      color: #000;
    }

    .scroll-hint {
      position: absolute;
      bottom: 30px;
      left: 50%;
      transform: translateX(-50%);
      color: var(--text-muted);
      font-size: 0.9rem;
      animation: bounce 2s infinite;
    }

    @keyframes bounce {
      0%, 20%, 50%, 80%, 100% {
        transform: translateX(-50%) translateY(0);
      }
      40% {
        transform: translateX(-50%) translateY(-10px);
      }
      60% {
        transform: translateX(-50%) translateY(-5px);
      }
    }

    /* Custom theme examples */
    .theme-warm {
      --constellation-background: linear-gradient(to bottom, #1a0a00 0%, #3d1a00 50%, #2d1000 100%);
    }

    .theme-ocean {
      --constellation-background: linear-gradient(to bottom, #000428 0%, #004e92 100%);
    }

    .theme-forest {
      --constellation-background: linear-gradient(to bottom, #0a1a0a 0%, #1a3a1a 50%, #0d2d0d 100%);
    }

    .theme-sunset {
      --constellation-background: linear-gradient(to bottom, #1a0a1a 0%, #4a1a4a 30%, #7a3a3a 70%, #3a1a1a 100%);
    }
JS (js)
import "https://esm.sh/@manufosela/constellation-sky";

    // Configurable demo controls
    const configurable = document.getElementById('configurable');

    // Star count
    document.getElementById('star-range').addEventListener('input', (e) => {
      configurable.starCount = parseInt(e.target.value);
      document.getElementById('star-value').textContent = e.target.value;
    });

    // Line distance
    document.getElementById('line-range').addEventListener('input', (e) => {
      configurable.lineDistance = parseInt(e.target.value);
      document.getElementById('line-value').textContent = e.target.value;
    });

    // Speed
    document.getElementById('speed-range').addEventListener('input', (e) => {
      configurable.speed = parseFloat(e.target.value);
      document.getElementById('speed-value').textContent = e.target.value;
    });

    // Star color
    document.getElementById('star-color').addEventListener('input', (e) => {
      configurable.starColor = e.target.value;
    });

    // Line color
    document.getElementById('line-color').addEventListener('input', (e) => {
      configurable.lineColor = e.target.value;
    });

    // Toggle lines
    document.getElementById('toggle-lines').addEventListener('click', () => {
      configurable.showLines = !configurable.showLines;
    });

    // Toggle pause
    const pauseBtn = document.getElementById('toggle-pause');
    pauseBtn.addEventListener('click', () => {
      if (configurable.paused) {
        configurable.resume();
        pauseBtn.textContent = 'Pause';
        pauseBtn.classList.remove('active');
      } else {
        configurable.pause();
        pauseBtn.textContent = 'Resume';
        pauseBtn.classList.add('active');
      }
    });

    // Reset
    document.getElementById('reset-btn').addEventListener('click', () => {
      configurable.reset();
    });