Matrix-inspired green-on-black design with character-by-character reveal.
Created
March 23, 2025 13:24
-
-
Save aldoyh/c203faf499bfce5b8f2ebd52dd9031c8 to your computer and use it in GitHub Desktop.
Hacker Text Scramble Glitch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="controls"> | |
<div class="control-group"> | |
<label for="charSet">Character Set:</label> | |
<select id="charSet" onchange="updateSettings()"> | |
<option value="tech1">Tech/Code Symbols 1</option> | |
<option value="tech2">Tech/Code Symbols 2</option> | |
<option value="math">Math & Binary</option> | |
<option value="cryptic">Cryptic/Alien</option> | |
<option value="mixed">Mixed Languages</option> | |
<option value="alphabet">Alphabet</option> | |
<option value="matrix1">Matrix 1</option> | |
<option value="matrix2">Matrix 2</option> | |
<option value="matrix3">Chinese Characters</option> | |
<option value="matrix4">Japanese Kanji</option> | |
<option value="emoji1">Emoji 1</option> | |
<option value="emoji2">Emoji 2</option> | |
<option value="emoji3">Emoji 3</option> | |
</select> | |
</div> | |
<div class="control-group"> | |
<label for="customText">Custom Text:</label> | |
<textarea id="customText" class="custom-text" placeholder="Enter custom text..."></textarea> | |
</div> | |
<div class="control-group"> | |
<label for="revealSpeed">Reveal Speed:</label> | |
<input type="range" id="revealSpeed" min="1" max="10" value="10" onchange="updateSettings()"> | |
</div> | |
<div class="control-group"> | |
<label for="changeFreq">Change Frequency:</label> | |
<input type="range" id="changeFreq" min="1" max="100" value="28" onchange="updateSettings()"> | |
</div> | |
<div class="control-group"> | |
<label for="glowIntensity">Glow Intensity</label> | |
<input type="range" id="glowIntensity" min="0" max="20" value="8" onchange="updateGlow()"> | |
</div> | |
<div class="control-group"> | |
<label>Colors:</label> | |
<div class="color-picker"> | |
<input type="color" id="bgColor" value="#111111" class="color-input" onchange="updateColors()"> | |
<input type="color" id="textColor" value="#00ff00" class="color-input" onchange="updateColors()"> | |
</div> | |
</div> | |
<button class="btn" onclick="playAnimation()">Reveal Text</button> | |
</div> | |
<div class="text-container" id="text"></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TextScramble { | |
constructor(el) { | |
this.el = el; | |
this.charSets = { | |
tech1: '!<>-_\\/[]{}—=+*^?#________', | |
tech2: '!<>-_\\/[]{}—=+*^?#$%&()~', | |
math: '01︎10︎101︎01︎+=-×÷', | |
cryptic: '¥¤§Ω∑∆√∞≈≠≤≥', | |
mixed: 'あ㐀明る日¥£€$¢₽₹₿', | |
alphabet: 'abcdefghijklmnopqrstuvwxyz', | |
matrix1: 'ラドクリフマラソンわたしワタシんょンョたばこタバコとうきょうトウキョウ', | |
matrix2: '日ハミヒーウシナモニサワツオリアホテマケメエカキムユラセネスタヌヘ', | |
matrix3: '字型大小女巧偉周年', | |
matrix4: '九七二人入八力十下三千上口土夕大女子小山川五天中六円手文日月木水火犬王正出本右四左玉生田白目石立百年休先名字早気竹糸耳虫村男町花見貝赤足車学林空金雨青草音', | |
emoji1: Array.from('😀😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚🤗🤔😐😑😶🙄😏😮😯😲😴🤤🤤😪😵🤯🤪🤩🥳🥺🥵🥴🥺'), | |
emoji2: Array.from('🏠🏢🏥🏦🏨🏫🏬🏭🏯🏰🏟️🎡🎢🎠⛲🎪🗼🗽🗿🌉'), | |
emoji3: Array.from('🍎🍊🍋🍌🍉🍇🍓🍈🍒🍑🥭🍍🥥🥝🥑🍆🥕🌽🌶️🍄🌰🍞') | |
}; | |
this.chars = this.charSets.tech1; | |
this.update = this.update.bind(this); | |
this.revealSpeed = 1; | |
this.changeFrequency = 0.28; | |
this.highlightColor = '#00ff88'; | |
this.glowIntensity = 8; | |
this.activeGlowIntensity = 12; | |
} | |
setCharSet(setName) { | |
if (this.charSets[setName]) { | |
this.chars = this.charSets[setName]; | |
return true; | |
} | |
return false; | |
} | |
setRevealSpeed(speed) { | |
// 1-10 scale, lower is faster | |
this.revealSpeed = 11 - speed; | |
} | |
setChangeFrequency(freq) { | |
// 1-100 scale | |
this.changeFrequency = freq / 100; | |
} | |
setHighlightColor(color) { | |
this.highlightColor = color; | |
} | |
setGlowIntensity(intensity) { | |
this.glowIntensity = intensity; | |
this.activeGlowIntensity = intensity + 4; | |
document.getElementById('text').style.textShadow = `0 0 ${intensity}px currentColor`; | |
} | |
setText(newText) { | |
const oldText = this.el.innerText; | |
const length = Math.max(oldText.length, newText.length); | |
const promise = new Promise(resolve => this.resolve = resolve); | |
this.queue = []; | |
for (let i = 0; i < length; i++) { | |
const from = oldText[i] || ''; | |
const to = newText[i] || ''; | |
const start = Math.floor(Math.random() * (40 / this.revealSpeed)); | |
const end = start + Math.floor(Math.random() * (40 / this.revealSpeed)); | |
this.queue.push({ from, to, start, end }); | |
} | |
cancelAnimationFrame(this.frameRequest); | |
this.frame = 0; | |
this.update(); | |
return promise; | |
} | |
update() { | |
let output = ''; | |
let complete = 0; | |
for (let i = 0, n = this.queue.length; i < n; i++) { | |
let { from, to, start, end, char } = this.queue[i]; | |
if (this.frame >= end) { | |
complete++; | |
output += to; | |
} else if (this.frame >= start) { | |
if (!char || Math.random() < this.changeFrequency) { | |
char = this.randomChar(); | |
this.queue[i].char = char; | |
} | |
output += `<span class="scrambling" style="color: ${this.highlightColor}; text-shadow: 0 0 ${this.activeGlowIntensity}px currentColor;">${char}</span>`; | |
} else { | |
output += from; | |
} | |
} | |
this.el.innerHTML = output; | |
if (complete === this.queue.length) { | |
this.resolve(); | |
} else { | |
this.frameRequest = requestAnimationFrame(this.update); | |
this.frame++; | |
} | |
} | |
randomChar() { | |
return this.chars[Math.floor(Math.random() * this.chars.length)]; | |
} | |
} | |
const phrases = [ | |
'Hello World', | |
'Secret Message Revealed', | |
'Access Granted', | |
'System Online', | |
'Loading Complete' | |
]; | |
let counter = 0; | |
const el = document.getElementById('text'); | |
const fx = new TextScramble(el); | |
function updateSettings() { | |
const charSet = document.getElementById('charSet').value; | |
const revealSpeed = parseInt(document.getElementById('revealSpeed').value); | |
const changeFreq = parseInt(document.getElementById('changeFreq').value); | |
fx.setCharSet(charSet); | |
fx.setRevealSpeed(revealSpeed); | |
fx.setChangeFrequency(changeFreq); | |
} | |
function updateColors() { | |
const bgColor = document.getElementById('bgColor').value; | |
const textColor = document.getElementById('textColor').value; | |
document.body.style.backgroundColor = bgColor; | |
document.body.style.color = textColor; | |
fx.setHighlightColor(shiftColor(textColor, 40)); | |
} | |
function updateGlow() { | |
const glowIntensity = parseInt(document.getElementById('glowIntensity').value); | |
fx.setGlowIntensity(glowIntensity); | |
} | |
function shiftColor(hex, lightnessDelta) { | |
// Simple function to shift a color's lightness | |
const r = parseInt(hex.slice(1, 3), 16); | |
const g = parseInt(hex.slice(3, 5), 16); | |
const b = parseInt(hex.slice(5, 7), 16); | |
const shift = (c) => { | |
const newVal = Math.min(255, c + lightnessDelta); | |
return newVal.toString(16).padStart(2, '0'); | |
}; | |
return `#${shift(r)}${shift(g)}${shift(b)}`; | |
} | |
function playAnimation() { | |
const customText = document.getElementById('customText').value.trim(); | |
const text = customText || phrases[counter]; | |
fx.setText(text).then(() => { | |
setTimeout(() => { | |
if (!customText) { | |
counter = (counter + 1) % phrases.length; | |
} | |
}, 2000); | |
}); | |
} | |
// Set initial colors | |
updateColors(); | |
// Set initial settings | |
updateSettings(); | |
// Set initial glow | |
updateGlow(); | |
// Initial animation | |
setTimeout(playAnimation, 1000); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
background-color: #111; | |
color: #0f0; | |
font-family: 'Courier New', monospace; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
margin: 0; | |
} | |
.text-container { | |
font-size: 2.5rem; | |
font-weight: bold; | |
min-height: 150px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
text-align: center; | |
text-shadow: 0 0 8px currentColor; | |
} | |
.scrambling { | |
text-shadow: 0 0 12px currentColor; | |
} | |
.controls { | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
display: flex; | |
flex-direction: column; | |
gap: 10px; | |
background-color: rgba(0,0,0,0.7); | |
padding: 15px; | |
border: 1px solid #0f0; | |
max-width: 300px; | |
box-shadow: 0 0 10px rgba(0, 255, 0, 0.3); | |
} | |
.control-group { | |
display: flex; | |
flex-direction: column; | |
margin-bottom: 10px; | |
} | |
.control-group label { | |
margin-bottom: 5px; | |
font-size: 0.8rem; | |
} | |
.btn, select, input[type="text"] { | |
padding: 8px 12px; | |
background-color: #333; | |
color: #0f0; | |
border: 1px solid #0f0; | |
cursor: pointer; | |
font-family: 'Courier New', monospace; | |
} | |
.btn:hover { | |
box-shadow: 0 0 10px rgba(0, 255, 0, 0.5); | |
} | |
.custom-text { | |
width: 100%; | |
resize: none; | |
height: 60px; | |
background-color: #333; | |
color: #0f0; | |
border: 1px solid #0f0; | |
font-family: 'Courier New', monospace; | |
margin-bottom: 10px; | |
} | |
.color-picker { | |
display: flex; | |
gap: 5px; | |
} | |
.color-input { | |
width: 50%; | |
} | |
.control-group:last-child { | |
margin-bottom: 0; | |
} | |
.control-group label span { | |
opacity: 0.8; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment