@manufosela/scene-stwtext

@manufosela/scene-stwtext

A Lit 3 web component for Star Wars style text crawl animation using CSS 3D perspective

Select Demo

EPISODE IV

A NEW HOPE

It is a period of civil war. Rebel spaceships, striking from a hidden base, have won their first victory against the evil Galactic Empire.

During the battle, Rebel spies managed to steal secret plans to the Empire's ultimate weapon, the DEATH STAR, an armored space station with enough power to destroy an entire planet.

Pursued by the Empire's sinister agents, Princess Leia races home aboard her starship, custodian of the stolen plans that can save her people and restore freedom to the galaxy....

THE COMPONENT AWAKENS

In a universe of endless frameworks, a new power has emerged. Web Components, the native solution that works everywhere, has begun its rise.

Developers across the galaxy have discovered the power of Lit, a simple yet powerful library for building fast, lightweight web components.

This component, scene-stwtext, brings the iconic Star Wars text crawl to any website. No external dependencies required. Just pure HTML, CSS, and JavaScript.

May the DOM be with you, always....

MINIMAL STYLE

Sometimes less is more. This demo shows the text crawl without the stars background and with a custom gradient.

Perfect for product announcements, project introductions, or any content that needs that dramatic reveal.

Customize the colors, speed, and perspective to match your brand.

Using slots for complete customization....

SLOTS DEMO

This demo uses slots for the intro text and logo area. You can insert any HTML content into these slots.

The default slot accepts the main crawl text content. Use h1 for titles and p for paragraphs.

Slots give you maximum flexibility while the component handles all the animation and 3D perspective magic.

CONFIGURABLE

Use the configuration panel on the left to adjust all the parameters in real-time.

Change the speed, perspective, colors, and more to see how they affect the animation.

Once you find settings you like, you can copy the values to use in your own implementation.

The component supports CSS custom properties for easy theming and JavaScript properties for dynamic control.

Configuration

Hover over the crawl to see playback controls. Click Restart to apply changes.

Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<!-- Demo Selector -->
  <div class="demo-selector">
    <h3>Select Demo</h3>
    <button class="active" data-demo="classic">Classic Star Wars</button>
    <button data-demo="custom">Custom Content</button>
    <button data-demo="minimal">Minimal</button>
    <button data-demo="slots">Using Slots</button>
    <button data-demo="config">Configurable</button>
  </div>

  <!-- Classic Star Wars Demo -->
  <div class="demo-container active" id="demo-classic">
    <scene-stwtext
      intro-text="A long time ago in a galaxy far, far away...."
      speed="60"
      perspective="400"
      fade-distance="30"
      intro-duration="4"
      logo-duration="5"
      show-stars
      show-controls
    >
      <h1>EPISODE IV</h1>
      <h1>A NEW HOPE</h1>
      <p>
        It is a period of civil war. Rebel spaceships, striking from a hidden base,
        have won their first victory against the evil Galactic Empire.
      </p>
      <p>
        During the battle, Rebel spies managed to steal secret plans to the Empire's
        ultimate weapon, the DEATH STAR, an armored space station with enough power
        to destroy an entire planet.
      </p>
      <p>
        Pursued by the Empire's sinister agents, Princess Leia races home aboard her
        starship, custodian of the stolen plans that can save her people and restore
        freedom to the galaxy....
      </p>
    </scene-stwtext>
  </div>

  <!-- Custom Content Demo -->
  <div class="demo-container" id="demo-custom">
    <scene-stwtext
      intro-text="Once upon a time, in a world of web components...."
      speed="50"
      perspective="450"
      show-stars
      show-controls
      style="--stwtext-text-color: #00ffcc; --stwtext-intro-color: #ff66cc;"
    >
      <h1>THE COMPONENT AWAKENS</h1>
      <p>
        In a universe of endless frameworks, a new power has emerged. Web Components,
        the native solution that works everywhere, has begun its rise.
      </p>
      <p>
        Developers across the galaxy have discovered the power of Lit, a simple yet
        powerful library for building fast, lightweight web components.
      </p>
      <p>
        This component, scene-stwtext, brings the iconic Star Wars text crawl to any
        website. No external dependencies required. Just pure HTML, CSS, and JavaScript.
      </p>
      <p>
        May the DOM be with you, always....
      </p>
    </scene-stwtext>
  </div>

  <!-- Minimal Demo -->
  <div class="demo-container" id="demo-minimal">
    <scene-stwtext
      speed="40"
      show-stars="false"
      show-controls
      style="
        --stwtext-background: linear-gradient(to bottom, #1a1a2e 0%, #16213e 100%);
        --stwtext-text-color: #fff;
      "
    >
      <h1>MINIMAL STYLE</h1>
      <p>
        Sometimes less is more. This demo shows the text crawl without the stars
        background and with a custom gradient.
      </p>
      <p>
        Perfect for product announcements, project introductions, or any content
        that needs that dramatic reveal.
      </p>
      <p>
        Customize the colors, speed, and perspective to match your brand.
      </p>
    </scene-stwtext>
  </div>

  <!-- Slots Demo -->
  <div class="demo-container" id="demo-slots">
    <scene-stwtext
      speed="55"
      perspective="500"
      intro-duration="3"
      logo-duration="4"
      show-stars
      show-controls
    >
      <span slot="intro">Using slots for complete customization....</span>
      <div slot="logo">
        <div class="sw-logo">YOUR LOGO</div>
      </div>
      <h1>SLOTS DEMO</h1>
      <p>
        This demo uses slots for the intro text and logo area. You can insert
        any HTML content into these slots.
      </p>
      <p>
        The default slot accepts the main crawl text content. Use h1 for titles
        and p for paragraphs.
      </p>
      <p>
        Slots give you maximum flexibility while the component handles all the
        animation and 3D perspective magic.
      </p>
    </scene-stwtext>
  </div>

  <!-- Configurable Demo -->
  <div class="demo-container" id="demo-config">
    <scene-stwtext
      id="configurable"
      intro-text="Customize everything below...."
      speed="60"
      perspective="400"
      fade-distance="30"
      show-stars
      show-controls
    >
      <h1>CONFIGURABLE</h1>
      <p>
        Use the configuration panel on the left to adjust all the parameters
        in real-time.
      </p>
      <p>
        Change the speed, perspective, colors, and more to see how they affect
        the animation.
      </p>
      <p>
        Once you find settings you like, you can copy the values to use in
        your own implementation.
      </p>
      <p>
        The component supports CSS custom properties for easy theming and
        JavaScript properties for dynamic control.
      </p>
    </scene-stwtext>

    <div class="config-panel">
      <h3>Configuration</h3>

      <label>
        Speed (seconds): <span id="speed-value">60</span>
        <input type="range" id="speed-range" min="20" max="120" value="60">
      </label>

      <label>
        Perspective: <span id="perspective-value">400</span>px
        <input type="range" id="perspective-range" min="200" max="800" value="400">
      </label>

      <label>
        Fade Distance: <span id="fade-value">30</span>%
        <input type="range" id="fade-range" min="10" max="50" value="30">
      </label>

      <label>
        Text Color
        <input type="color" id="text-color" value="#ffd700">
      </label>

      <label>
        Intro Color
        <input type="color" id="intro-color" value="#44eeee">
      </label>

      <p class="info-text">
        Hover over the crawl to see playback controls.
        Click Restart to apply changes.
      </p>
    </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;
}

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

    .demo-selector {
      position: fixed;
      top: 20px;
      right: 20px;
      z-index: 100;
      background: rgba(0, 0, 0, 0.8);
      padding: 20px;
      border-radius: 10px;
      border: 1px solid var(--border);
    }

    .demo-selector h3 {
      margin-bottom: 15px;
      color: #ffd700;
    }

    .demo-selector button {
      display: block;
      width: 100%;
      padding: 10px 15px;
      margin-bottom: 10px;
      background: rgba(255, 215, 0, 0.1);
      border: 1px solid #ffd700;
      color: #ffd700;
      cursor: pointer;
      border-radius: 4px;
      transition: all 0.2s;
    }

    .demo-selector button:hover {
      background: rgba(255, 215, 0, 0.3);
    }

    .demo-selector button.active {
      background: #ffd700;
      color: #000;
    }

    .demo-container {
      display: none;
    }

    .demo-container.active {
      display: block;
    }

    scene-stwtext {
      display: block;
      height: 100vh;
    }

    /* Custom Star Wars logo text */
    .sw-logo {
      font-family: 'Star Jedi', 'Franklin Gothic Medium', Arial, sans-serif;
      font-size: 4rem;
      color: #ffd700;
      text-align: center;
      letter-spacing: 0.2em;
    }

    /* Config panel */
    .config-panel {
      position: fixed;
      bottom: 20px;
      left: 20px;
      z-index: 100;
      background: rgba(0, 0, 0, 0.9);
      padding: 20px;
      border-radius: 10px;
      border: 1px solid var(--border);
      max-width: 300px;
    }

    .config-panel h3 {
      margin-bottom: 15px;
      color: #ffd700;
    }

    .config-panel label {
      display: block;
      margin-bottom: 15px;
      font-size: 0.9rem;
      color: var(--text-muted);
    }

    .config-panel input[type="range"] {
      width: 100%;
      margin-top: 5px;
    }

    .config-panel input[type="color"] {
      width: 100%;
      height: 30px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    .info-text {
      color: var(--text-muted);
      font-size: 0.8rem;
      margin-top: 10px;
    }
JS (js)
import "https://esm.sh/@manufosela/scene-stwtext";

    // Demo selector functionality
    const demoButtons = document.querySelectorAll('.demo-selector button');
    const demoContainers = document.querySelectorAll('.demo-container');

    demoButtons.forEach(button => {
      button.addEventListener('click', () => {
        const demoId = button.dataset.demo;

        // Update active button
        demoButtons.forEach(b => b.classList.remove('active'));
        button.classList.add('active');

        // Show selected demo
        demoContainers.forEach(container => {
          container.classList.remove('active');
          if (container.id === `demo-${demoId}`) {
            container.classList.add('active');

            // Restart animation when switching demos
            const stwtext = container.querySelector('scene-stwtext');
            if (stwtext) {
              setTimeout(() => stwtext.restart(), 100);
            }
          }
        });

        // Show/hide config panel
        const configPanel = document.querySelector('.config-panel');
        if (configPanel) {
          configPanel.style.display = demoId === 'config' ? 'block' : 'none';
        }
      });
    });

    // Configuration panel for configurable demo
    const configurable = document.getElementById('configurable');
    const configPanel = document.querySelector('.config-panel');

    if (configPanel) {
      configPanel.style.display = 'none'; // Hide initially

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

      // Perspective
      document.getElementById('perspective-range').addEventListener('input', (e) => {
        configurable.perspective = parseInt(e.target.value);
        document.getElementById('perspective-value').textContent = e.target.value;
      });

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

      // Text color
      document.getElementById('text-color').addEventListener('input', (e) => {
        configurable.style.setProperty('--stwtext-text-color', e.target.value);
      });

      // Intro color
      document.getElementById('intro-color').addEventListener('input', (e) => {
        configurable.style.setProperty('--stwtext-intro-color', e.target.value);
      });
    }