Skip to content

Instantly share code, notes, and snippets.

@tuliopc23
Created July 8, 2025 21:07
Show Gist options
  • Select an option

  • Save tuliopc23/e896fe7b40513b2d2a1ef674968f3b13 to your computer and use it in GitHub Desktop.

Select an option

Save tuliopc23/e896fe7b40513b2d2a1ef674968f3b13 to your computer and use it in GitHub Desktop.
Hacker Lightning (wip)
<div id="hackerLightning" onclick="animateBolts()"><div>
const DICTIONARY = "0123456789qwertyuiopasdfghjklzxcvbnm".split('');
const LETTER_TOTAL = 406;
const CENTER_WORD = 'hacker lightning';
const CW_START = LETTER_TOTAL/2 - CENTER_WORD.length/2;
const CW_END = CW_START + CENTER_WORD.length;
const ROW_LENGTH = 45;
var getBoltStartingPositions = function() {
var results = [];
results.push(CW_START);
results.push(CW_END + 1);
for(var i = CW_START; i < CW_END + 1; i++) {
var top = i - ROW_LENGTH;
var bottom = i + ROW_LENGTH+1;
results.push(top, bottom);
}
return results;
}
const STARTING_POSITIONS = getBoltStartingPositions();
var el = document.getElementById('hackerLightning');
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var genRanChar = function() {
var index = Math.floor(Math.random() * DICTIONARY.length);
return DICTIONARY[index];
}
var genRanString = function(amt) {
var string = ``;
var wordIndex = 0;
for(var i = 0; i < amt; i++) {
if(i >= CW_START && i < CW_END) {
string += `<span class="static">${CENTER_WORD[wordIndex]}</span>`;
wordIndex++;
}
else {
string += `<span>${genRanChar()}</span>`;
}
}
return string;
}
function pickRandomProperty(obj) {
var result;
var count = 0;
for (var prop in obj)
if (Math.random() < 1/++count)
result = prop;
return result;
}
var Bolt = function() {
this.position = STARTING_POSITIONS[getRandomIntInclusive(0, STARTING_POSITIONS.length)];
this.lastDirection = '';
this.moves = {
left: -1,
right: 1,
up: -ROW_LENGTH,
down: ROW_LENGTH
}
this.move = function() {
var direction = pickRandomProperty(this.moves);
while(direction === this.lastDirection) {
direction = pickRandomProperty(this.moves);
}
this.lastDirection = direction;
var move = this.moves[direction];
var current = document.querySelector(`#hackerLightning span:nth-child(${this.position})`);
var next = document.querySelector(`#hackerLightning span:nth-child(${this.position += move})`);
if(next) {
current.style.opacity = 1;
current.style.color = 'rgb(40,23,64)';
next.style.opacity = 1;
next.style.color = '#fff';
}
else {
current.style.opacity = 1;
current.style.color = 'rgb(40,23,64)';
return false;
}
}
this.strike = function() {
var self = this;
var animate = setInterval(function() {
var move = self.move();
if(move === false) {
clearInterval(animate);
}
}, 16);
}
}
el.innerHTML = genRanString(LETTER_TOTAL);
var genBolts = function(amt) {
var results = [];
for(var i = 0; i < amt; i++) {
results.push(new Bolt());
}
return results;
}
var animateBolts = function() {
var bolts = genBolts(15);
for(var i = 0; i < bolts.length; i++) {
bolts[i].strike();
}
}
animateBolts();
html,
body {
margin: 0;
width: 100%;
height: 100%;
}
body {
font-family: 'Roboto Mono', monospace;
background-color: darken(rgb(40,23,64), 10%);
font-size: 3.7vw;
display: flex;
align-items: center;
justify-content: center;
}
div {
width: 100vw;
height: auto;
color: #fff;
word-break: break-all;
overflow: hidden;
text-transform: uppercase;
span {
display: inline-block;
opacity: 0;
color: rgb(40,23,64);
transition: opacity 0s ease;
&.static {
opacity: 1 !important;
color: #fff !important;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment