Create a Star Wars-Like Crawl Using CSS & JavaScript

If you're a web developer (or want to be), then you're probably a geek and you like Star Wars. Well, how would you like to have the Star Wars opening crawl as a background for your next website? š
The answer, of course, is YAAAAAS! Read on....
I tried many iterations of this (because I really really wanted it). First I tried using a stock video of traveling through space, but the file size was too large and Google Lighthouse complained. I tried compressing to webm
format but that only works on some devices (not iOS) and looks terrible and pixelated.
After hours of playing around, I decided to use the HTML5 canvas element and JavaScript to render the stars and CSS keyframes to render the 3D crawling text. As for the font, I downloaded a mock-Star Wars font called "Deathstar". You can find those here.
Check out this working example.
And now for the code:
// stars.js // Get canvas element by its ID var field = document.getElementById("field"); // Make sure field canvas exists var f = (typeof field.getContext === 'function') ? field.getContext("2d") : null; // Config var stars = {}; var starIndex = 0; var numStars = 0; var acceleration = 1; var starsToDraw = (field.width * field.height) / 200; function Star() { this.X = field.width / 2; this.Y = field.height / 2; this.SX = Math.random() * 10 - 5; this.SY = Math.random() * 10 - 5; var start = 0; if (field.width > field.height) start = field.width; else start = field.height; this.X += this.SX * start / 10; this.Y += this.SY * start / 10; this.W = 1; this.H = 1; this.age = 0; this.dies = 500; starIndex++; stars[starIndex] = this; this.ID = starIndex; this.C = "#ffffff"; } Star.prototype.Draw = function () { if (!f) { console.log('Could not load canvas element'); return; } this.X += this.SX; this.Y += this.SY this.SX += this.SX / (50 / acceleration); this.SY += this.SY / (50 / acceleration); this.age++; if (this.age == Math.floor(50 / acceleration) | this.age == Math.floor(150 / acceleration) | this.age == Math.floor(300 / acceleration)) { this.W++; this.H++; } if (this.X + this.W < 0 | this.X > field.width | this.Y + this.H < 0 | this.Y > field.height) { delete stars[this.ID]; numStars--; } f.fillStyle = this.C; f.fillRect(this.X, this.Y, this.W, this.H); } field.width = window.innerWidth; field.height = window.innerHeight; function draw() { if (!f) { console.log('Could not load canvas element'); return; } if (field.width != window.innerWidth) field.width = window.innerWidth; if (field.height != window.innerHeight) field.height = window.innerHeight; // The alpha value can be adjusted to create a stream effect f.fillStyle = "rgba(0, 0, 0, 0.6)"; f.fillRect(0, 0, field.width, field.height); for (var i = numStars; i < starsToDraw; i++) { new Star(); numStars++; } for (var star in stars) { stars[star].Draw(); } } // Modify interval to adjust speed if (f) setInterval(draw, 40);
And the CSS:
/* global.css */ body { margin: 0; padding: 0; background-color: black; } main { width: 100vw; height: 100vh; } #field { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: -3; } #crawl { position: fixed; top: 0; bottom: 0; z-index: -2; font-family: Deathstar, Verdana, Geneva, Tahoma, sans-serif; text-align: center; color: white; font-size: 4rem; perspective: 200px; } #crawl p { transform: rotateX(20deg); animation: starwars 30s ease-in; animation-iteration-count: infinite; margin: 0 auto; } #crawl p span { font-size: 150%; } #overlay { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; background-color: rgba(0, 0, 0, 0.4); } @keyframes starwars { 0% { transform: rotateX(20deg) translateY(750px); } 100% { transform: rotateX(20deg) translateY(-1500px); } } @keyframes starwars1200 { 0% { transform: rotateX(20deg) translateY(565px); } 100% { transform: rotateX(20deg) translateY(-1500px); } } @media only screen and (max-width: 1200px) { #crawl { font-size: 1rem; } #crawl p { animation: starwars1200 30s ease-in; } } @font-face { font-family: 'Deathstar'; font-style: normal; font-weight: 100; font-display: swap; src: url('https://cdn.designly.biz/fonts/deathstar/death_star-webfont.eot'); src: local(''), url('https://cdn.designly.biz/fonts/deathstar/death_star-webfont.eot?#iefix') format('embedded-opentype'), url('https://cdn.designly.biz/fonts/deathstar/death_star-webfont.woff2') format('woff2'), url('https://cdn.designly.biz/fonts/deathstar/death_star-webfont.woff') format('woff'), url('https://cdn.designly.biz/fonts/deathstar/deathstar.otf') format('opentype'), url('https://cdn.designly.biz/fonts/deathstar/death_star-webfont.svg') format('svg'); }
The CSS could definitely use some fine tuning, including additional breakpoints. The downside to this code is that you have to adjust the CSS if you change the length of the text. But if your text is static then this should work nicely.
And last but not least, the HTML:
<html lang="en"> <head> <meta name="robots" content="index, follow" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=yes" /> <link rel="stylesheet" href="css/global.css" /> </head> <body> <main> <canvas id="field"></canvas> <div id="crawl"> <p> <span>Episode IV</span> <br /><br /> A New Hope <br /><br /> It is a period of civil war. Rebel spaceships, striking from a hidden base, have won their first victory against the evil Galactic Empire. <br /><br /> 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. <br /> <br /> 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> </div> <div id="overlay"></div> </main> </body> <script src="js/stars.js"></script> </html>
I hope you found this article helpful. You're welcome to use my copy of the Deathstar font from my CDN for non-commercial purposes only. Otherwise, please download and host your own. If you're not sure how to do that, check out this article.
You can find the code for this example on GitHub. Feel free to download or clone it.
For more great information about web dev and systems administration, please read the Designly Blog. š
Please Share and Like!
Comments
About The Author

Jay Simons
Jay is a full-stack developer, electrical engineer, writer and music producer. He currently resides in the Madison, WI area.
šLinked In šJaySudo.com