DEV Community 👩‍💻👨‍💻

Ian
Ian

Posted on

Create Custom Twitch Overlays With Svelte!

twitch overlay preview

Introduction

Hey there, my name is Ian and I stream myself coding on Twitch. I keep my stream pretty basic, but I thought maybe an overlay would bring more viewers in. I started thinking...

  • Should I buy an overlay?
  • Are there any free overlays that I like?
  • How do I get animations on my overlay?

Then it occurred to me, I'm a developer! Why don't I just make one myself?
My graphic design skills are definitely not good. However, I can make some pretty cool websites.
So that's what I did, I made a website in Svelte that acts as my overlay and today I plan on teaching you how I did just that.

Prerequisites

OBS

OBS is a free and open source software used for Live Streaming.
To make this possible, we'll be using OBS's "Browser Source" feature. I use Streamlabs (an abstraction over OBS) however this feature is still available in the vanilla OBS software.

A Browser Source allows us to render a website or local html file directly onto our stream with a transparent background. Once we've rendered the website onto our stream, we'll use "Chroma Key" filters to filter out the color green from the Browser Source.

Svelte

I chose Svelte for this project because:

  1. I've never used it for a project before.
  2. It's simple and fast to setup.
  3. This project isn't super complicated so something like React seems a bit "overkill".

Setting up a Svelte project is super easy. Simply run this command!

npm init vite my-app -- --template svelte
Enter fullscreen mode Exit fullscreen mode

Note, this won't be a tutorial for Svelte. However, Svelte is quite similar to regular HTML/CSS/JavaScript development with a few caveats. Svelte provides an excellent learning tool at svelte.dev/tutorial/basics

svelte-hash-router

We'll be hosting our overlays on Github Pages, so it's essential that our routing works for this environment. Normal Single-Page-Application (SPA) routing doesn't mix well with Github pages as each route is pointed to a specific hosted page. Hash Routing allows us to have SPA routing without confusing Github about what page we want. We'll be using svelte-hash-router to route our pages.

Install it in your Svelte project by using the command:

npm install --save svelte-hash-router
Enter fullscreen mode Exit fullscreen mode

Getting Started

Running Your Svelte App

First, let's run our Svelte app. In your project directory run:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Adding a Browser Source

Copy the localhost URL, right click in your "Sources" section of your streaming software and add a "Browser Source". Simply paste your localhost URL into the URL section of the "Browser Source".

Here are my Browser Source Settings:
browser source settings

Folder Structure

Once you've gotten your Svelte project running and added to your streaming software, it's time to create some directories and files.

First, make two directories,

  1. components
  2. pages

Components will be used to store our reusable code, pages will be used to store our different OBS "Scene" Overlays.

Go ahead and add your first page into your pages directory, I'll call mine Home.svelte. This page will be the main Overlay you use for your stream.

Routing

Next, let's setup our routing. In your main.js paste this code.

import App from './App.svelte';
import { routes } from 'svelte-hash-router'
import { Home } from './pages'

routes.set({
  '/': Home,
});

const app = new App({
  target: document.body,
});


export default app;
Enter fullscreen mode Exit fullscreen mode

All we're doing here is setting up routing and starting our App.

Setup Our App.svelte

We need to do some setup in our App.svelte. First we will import our Router we just configured and run it, then we will add some CSS.
For the CSS, let's start with a clean slate by removing margin and padding from the html and body tags. Import a fancy font from Google Fonts, and set the box-sizing to border-box to avoid any weird padding and border sizing with our elements.

<script>
  import Router from 'svelte-hash-router'
</script>

<main class="App">
  <Router/>
</main>

<style>
  @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&display=swap');

  :global(*) {
    font-family: 'Fira Code', monospace;
    box-sizing: border-box;
  }

  :global(html), :global(body) {
    margin: 0;
    padding: 0;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Now that we've gotten the groundwork done, let's start building the actual overlay.

Building the Overlay

Helpful Tip For Positioning Elements

One nice thing about adding a Browser Source to your streaming software is you can see it update live in relation to your other stream sources. However, it would be quite difficult and time consuming to guess what the top, left, right, and bottom values are for your camera to add a border around it. Instead, let's apply a full screen image of our stream as the background of our page, so it's easier to know where our elements are in relation to our stream.

<script>
</script>

<main class="Home"></main>

<style>
  .Home {
    width: 100vw;
    height: 100vh;
    background: url('<your_stream_image_here>');
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Your First Overlay

Time for the fun part, let's add a Web Cam Overlay!
I wanted to challenge myself a bit and make a animated gradient border with an accompanying animated gradient dropshadow. I know, it sounds like a lot, but that's why I'm here 😊

Let's start by making our first reusable component Camera.svelte in our components directory.

// components/Camera.svelte
<div class="Camera__outer">
  <div class="Camera__inner">
    <div class="Camera__shadow"></div>
    <div class="Camera__border"></div>
    <div class="Camera__section"></div>
    <div class="Camera__details">
      <div class="Camera__details-title">
        <h3>your_stream_name_here!</h3>
      </div>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

There's a bit to process here so let's break it down.

  • Camera__outer is the screen we use to position our Camera. It will have a width of 100vw and a height of 100vh.
  • Camera__inner is the actual camera container.
  • Camera__shadow is going to be our gradient drop shadow.
  • Camera__border is going to be our gradient border.
  • Camera__section will be our camera's green screen. (will be used for Chroma Key filter later on)
  • Camera__details is just a little spot to put some details for your stream. I'm just putting my name

Now it's time to style our Camera component.

Positioning and Sizing our Camera Component

First we need to get our elements to be the size we want, and to be where we want.

<script></script>

<div class="Camera__outer">
  <div class="Camera__inner">
    <div class="Camera__shadow"></div>
    <div class="Camera__border"></div>
    <div class="Camera__section"></div>
    <div class="Camera__details">
      <div class="Camera__details-title">
        <h3>your_stream_name_here!</h3>
      </div>
    </div>
  </div>
</div>

<style>
  .Camera__outer {
    /* lets use position our camera along the page with top, left, right, and bottom */
    position: relative;
    width: 100vw;
    height: 100vh;
  }

  .Camera__inner {
    position: absolute;
    
    /* below sizing/positioning is up to you! */
    top: 20px;
    right: 20px;
    width: 569px; 
    height: 330px;
  }

  .Camera__border, .Camera__shadow {
    /* width and height of our .Camera__innner */
    width: 100%;
    height: 100%;
  }

  .Camera__section, .Camera__border, .Camera__shadow {
    /* Stack Elements on top of each other */
    position: absolute;
    top: 0;
    left: 0;

    /* so we can see our elements, will be removed later */
    border: 1px solid yellow; 
  }

</style>
Enter fullscreen mode Exit fullscreen mode

Let's add it to our Home.svelte file now.

<script>
  import Camera from '../components/Camera.svelte'
</script>

<main class="Home">
  <Camera />
</main>

<style>
  .Home {
    width: 100vw;
    height: 100vh;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

After writing this code you should see something like this:
positioning-and-sizing

Fancy Animated Gradient Dropshadow

How are we going to animate a dropshadow? Well, the trick is to simply blur a gradient square and put it under all other elements. Then animate said gradient square.

Let's start with the gradient square.

.Camera__shadow {
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
  border-radius: 25px;
}
Enter fullscreen mode Exit fullscreen mode

Next, let's blur it.

.Camera__shadow {
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
  border-radius: 25px;
  filter: blur(.3rem);
}
Enter fullscreen mode Exit fullscreen mode

Then let's set the background size to 200%, and animate the gradient!

@keyframes glowingMovingGradient {
  0% {
    /* we'll increase the blur to make a glowing effect */
    filter: blur(.3rem);
    /* shift the background position to make the gradient move */
    background-position: 0% 50%;
  }

  50% {
    filter: blur(.5rem);
    background-position: 100% 50%;
  }

  100% {
    filter: blur(.7rem);
    background-position: 0% 50%;
  }
}

.Camera__shadow {
  animation: glowingMovingGradient 10s ease infinite alternate-reverse;
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);

  /* allows us to move the gradient around in our aniamtion */
  background-size: 200% 200%;
  
  border-radius: 25px;
  filter: blur(.3rem);
}
Enter fullscreen mode Exit fullscreen mode

Now you should have something like this!
animated-gradient-dropshadow

Fancy Animated Gradient Border

This part will be very similar to the one above. We're basically doing the same thing without the blur.

@keyframes movingGradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

.Camera__border {
  /* animated gradient */
  animation: movingGradient 10s ease infinite alternate-reverse;
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
  /* used for animating gradient */
  background-size: 200% 200%;
  background-position: 0% 0%;
  border-radius: 25px;
}
Enter fullscreen mode Exit fullscreen mode

Green Screen Time!

So even though our Browser Source's background is transparent our Gradient Border and Drop Shadows are not. To fix this, we'll build a mini green screen for us to use with a Chroma Key filter in OBS. That's where our .Camera__section comes into play.

.Camera__section {
  /* center .Camera__section */
  position: relative;
  top: 50%;
  left: 50%;    
  transform: translate(-50%, -50%);
  /* for green screen ChromaKey */
  background: #04ff00ff;
  border-radius: 20px;
  /* we want it to be a bit smaller than our border and drop shadow */
  height: 310px;
  width: 549px;
}
Enter fullscreen mode Exit fullscreen mode

Almost To The Finish Line

This will be the result of all our code from above:
gradient-border-dropshadow-greenscreen

Now all we have to do is apply our Chroma Key filter!
Here are the steps for Streamlabs:

  1. Right click on your source.
  2. Select "Filters"
  3. Select "Edit Filters"
  4. Click "+ Add Filter"
  5. Select "Chroma Key" in the Filter list.

Here are my Chroma Key Filter settings:
chrome key filter settings

Now all you have to do is add your camera to your OBS Scene and position it accordingly.

Last but Not Least

Hosting! This step is quite simple, just build your project and upload it to a Github Pages repository!

npm run build
Enter fullscreen mode Exit fullscreen mode

This command will generate a build directory in your public directory. You'll want to upload the entire public directory to your Github repository.

Then access your different overlays by going to http://yourgithubusername.github.io/your-repo-name/#/your-overlay-name

Conclusion

Congrats, you've coded your own Twitch Overlay!🥳
This is simply a tutorial to get started, the possibilities are endless. Hook this bad boy up to a WebSocket Server + Twitch Chat Bot and you can create anything.

If you made it this far, hopefully, you enjoyed your read and learned something too! If you'd like to follow me on other platforms, I stream on twitch, and you can also find me on twitter.

Thanks for reading!

Top comments (0)

🤔 Did you know?

 
DEV has a variety of tags to help you find the content you like. Find and follow your favorite tags.