@manufosela/animation-solarsystem

@manufosela/animation-solarsystem

SVG animated solar system web component built with Lit 3

Animation Solar System Demo

Event Log (click a planet)

Themed Example

Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<div class="demo-container">
      <h1>Animation Solar System Demo</h1>

      <div class="component-wrapper">
        <animation-solarsystem id="solarSystem"></animation-solarsystem>
      </div>

      <div class="controls">
        <div class="control-group">
          <label>Speed: <span id="speedValue">1</span>x</label>
          <input type="range" id="speedSlider" min="0.1" max="5" step="0.1" value="1" />
        </div>

        <div class="control-group">
          <label>Scale: <span id="scaleValue">1</span>x</label>
          <input type="range" id="scaleSlider" min="0.3" max="1.5" step="0.1" value="1" />
        </div>

        <div class="control-group">
          <label>Show Labels</label>
          <input type="checkbox" id="labelsToggle" checked />
        </div>

        <div class="control-group">
          <label>Show Orbits</label>
          <input type="checkbox" id="orbitsToggle" checked />
        </div>

        <button id="pauseBtn">Pause</button>
        <button id="resetBtn">Reset</button>
      </div>

      <div class="event-log">
        <h3>Event Log (click a planet)</h3>
        <div id="logContent"></div>
      </div>

      <h2 style="text-align: center; margin: 3rem 0 1rem">Themed Example</h2>

      <div class="component-wrapper">
        <animation-solarsystem class="themed-solar-system" speed="0.5"></animation-solarsystem>
      </div>
    </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;
}

<script type="module" src="../src/animation-solarsystem.js"></script>
    
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }

      h1 {
        text-align: center;
        margin-bottom: 2rem;
        font-weight: 300;
        letter-spacing: 2px;
      }

      .demo-container {
        max-width: 1200px;
        margin: 0 auto;
      }

      .component-wrapper {
        display: flex;
        justify-content: center;
        margin-bottom: 2rem;
      }

      .controls {
        display: flex;
        flex-wrap: wrap;
        gap: 1rem;
        justify-content: center;
        margin-bottom: 2rem;
        padding: 1.5rem;
        background: rgba(255, 255, 255, 0.1);
        border-radius: 12px;
        backdrop-filter: blur(10px);
      }

      .control-group {
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
      }

      .control-group label {
        font-size: 0.875rem;
        opacity: 0.8;
      }

      button {
        padding: 0.75rem 1.5rem;
        border: none;
        border-radius: 8px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        font-size: 1rem;
        cursor: pointer;
        transition: transform 0.2s, box-shadow 0.2s;
      }

      button:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
      }

      button:active {
        transform: translateY(0);
      }

      input[type='range'] {
        width: 150px;
        accent-color: #667eea;
      }

      input[type='checkbox'] {
        width: 20px;
        height: 20px;
        accent-color: #667eea;
      }

      .event-log {
        max-width: 600px;
        margin: 2rem auto;
        padding: 1rem;
        background: rgba(0, 0, 0, 0.3);
        border-radius: 8px;
        font-family: monospace;
        font-size: 0.875rem;
        max-height: 150px;
        overflow-y: auto;
      }

      .event-log h3 {
        margin-bottom: 0.5rem;
        font-weight: 500;
      }

      .event-item {
        padding: 0.25rem 0;
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
      }

      /* Custom theming example */
      .themed-solar-system {
        --solarsystem-width: 500px;
        --solarsystem-height: 500px;
        --solarsystem-background: radial-gradient(ellipse at center, #2d1b4e 0%, #1a0a2e 100%);
        --solarsystem-sun-color: #ff6b6b;
        --solarsystem-sun-glow: #ff4757;
        --solarsystem-orbit-color: rgba(255, 107, 107, 0.3);
        --solarsystem-label-color: #ffeaa7;
      }
JS (js)
const solarSystem = document.getElementById('solarSystem');
      const speedSlider = document.getElementById('speedSlider');
      const scaleSlider = document.getElementById('scaleSlider');
      const labelsToggle = document.getElementById('labelsToggle');
      const orbitsToggle = document.getElementById('orbitsToggle');
      const pauseBtn = document.getElementById('pauseBtn');
      const resetBtn = document.getElementById('resetBtn');
      const logContent = document.getElementById('logContent');

      speedSlider.addEventListener('input', (e) => {
        const value = parseFloat(e.target.value);
        solarSystem.speed = value;
        document.getElementById('speedValue').textContent = value.toFixed(1);
      });

      scaleSlider.addEventListener('input', (e) => {
        const value = parseFloat(e.target.value);
        solarSystem.scale = value;
        document.getElementById('scaleValue').textContent = value.toFixed(1);
      });

      labelsToggle.addEventListener('change', (e) => {
        solarSystem.showLabels = e.target.checked;
      });

      orbitsToggle.addEventListener('change', (e) => {
        solarSystem.showOrbits = e.target.checked;
      });

      pauseBtn.addEventListener('click', () => {
        solarSystem.toggle();
        pauseBtn.textContent = solarSystem.paused ? 'Resume' : 'Pause';
      });

      resetBtn.addEventListener('click', () => {
        solarSystem.reset();
      });

      solarSystem.addEventListener('planet-click', (e) => {
        const planet = e.detail.planet;
        const logItem = document.createElement('div');
        logItem.className = 'event-item';
        logItem.textContent = `Clicked: ${planet.name} (size: ${planet.size}, orbit: ${planet.orbitRadius}px)`;
        logContent.prepend(logItem);

        // Keep only last 10 entries
        while (logContent.children.length > 10) {
          logContent.removeChild(logContent.lastChild);
        }
      });