Added threejs video holo component visualiser, and text scramble on hero page

This commit is contained in:
AdamBtech
2025-05-22 23:53:03 +02:00
parent 11fd702957
commit 6a34aee9a8
9 changed files with 1009 additions and 6 deletions

View File

@@ -0,0 +1,17 @@
/* hero-display.component.css */
.scramble-text-glow {
text-shadow:
0 0 5px rgba(255, 255, 255, 0.3),
0 0 10px rgba(255, 255, 255, 0.2),
0 0 15px rgba(255, 255, 255, 0.1);
transition: text-shadow 0.3s ease;
}
/* Enhanced glow for binary characters */
.binary-glow {
text-shadow:
0 0 3px rgba(255, 255, 255, 0.4),
0 0 6px rgba(255, 255, 255, 0.3),
0 0 9px rgba(255, 255, 255, 0.2);
}

View File

@@ -1,4 +1,15 @@
<section class="">
<article class="border-b-1 h-100 flex items-center justify-center"><p class="text-9xl font-terminal-retro">HERO SECTION</p></article>
<article class="border-b-1 h-100 flex items-center justify-center checkered-bg-dark"><p class="font-terminal-nier text-9xl">CREATIVE DEVELOPER</p></article>
<!-- Video Section -->
<article class="border-b h-[40vh] sm:h-[60vh] md:h-[50vh] flex items-center justify-center">
<app-holo-video-container containerClasses="w-full aspect-video" videoSrc="cyber_hands.mp4" />
</article>
<!-- Display Text Section -->
<article class="flex-1 flex items-center justify-center checkered-bg-dark py-4 sm:py-8 md:py-12">
<p class="font-terminal-nier scramble-text-glow
text-6xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl 2xl:text-9xl
text-center px-4 leading-tight">
{{ displayText }}
</p>
</article>
</section>

View File

@@ -1,11 +1,198 @@
import { Component } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HoloVideoContainerComponent } from '../../shared/ui/holo-video-container/holo-video-container.component';
@Component({
selector: 'app-hero-display',
imports: [],
imports: [HoloVideoContainerComponent],
templateUrl: './hero-display.component.html',
styleUrl: './hero-display.component.css'
styleUrl: './hero-display.component.css',
})
export class HeroDisplayComponent {
export class HeroDisplayComponent implements OnInit, OnDestroy {
displayText: string = '';
private messageQueue: string[] = [
'Web Developer',
'Coding Enjoyer',
'Software Artisan',
];
private currentMessage: string = '';
private isGlitching: boolean = false;
private frameRequest: number | null = null;
private processTimeout: any = null;
private isInitialMount: boolean = true;
ngOnInit(): void {
this.initialMountAnimation();
}
ngOnDestroy(): void {
this.cleanup();
}
private cleanup(): void {
if (this.frameRequest) {
cancelAnimationFrame(this.frameRequest);
}
if (this.processTimeout) {
clearTimeout(this.processTimeout);
}
}
private initialMountAnimation(): void {
const firstMessage = this.messageQueue[0];
let currentIndex = 0;
const animateNextLetter = (): void => {
if (currentIndex <= firstMessage.length) {
let output = '';
// Build the confirmed part
for (let i = 0; i < currentIndex; i++) {
output += firstMessage[i];
}
// Add intense scrambling for upcoming letters (very fast scramble)
const scrambleLength = Math.min(6, firstMessage.length - currentIndex);
for (let i = 0; i < scrambleLength; i++) {
output += Math.random() > 0.5 ? '0' : '1';
}
this.displayText = output;
if (currentIndex < firstMessage.length) {
currentIndex++;
setTimeout(animateNextLetter, 35 + Math.random() * 25); // Much faster: 35-60ms
} else {
// Mount animation complete, start normal cycle
this.displayText = firstMessage;
this.currentMessage = firstMessage;
this.messageQueue.shift(); // Remove the first message since we used it
this.isInitialMount = false;
// Start the regular cycle after a short pause
setTimeout(() => {
this.processQueue();
}, 2000);
}
}
};
animateNextLetter();
}
private processQueue(): void {
if (this.messageQueue.length === 0) {
this.messageQueue = [
'Web Developer',
'Coding Enjoyer',
'Software Artisan',
];
}
const nextMessage = this.messageQueue.shift()!;
this.startScrambleAnimation(nextMessage);
this.processTimeout = setTimeout(() => {
this.processQueue();
}, 6000); // Reduced from 10000 to 6000 (faster rotation)
}
private startScrambleAnimation(nextMessage: string): void {
const length = Math.max(this.displayText.length, nextMessage.length);
let complete = 0;
const update = (): void => {
let output = '';
const scrambleChars = 3 + Math.random() * 5;
for (let i = 0; i < length; i++) {
const scramble = i < scrambleChars + complete && Math.random() > 0.8;
if (i < nextMessage.length) {
if (scramble) {
output += Math.random() > 0.5 ? '0' : '1';
} else if (i < complete) {
output += nextMessage[i];
} else {
output += this.displayText[i] || (Math.random() > 0.5 ? '0' : '1');
}
}
}
this.displayText = output;
if (complete < nextMessage.length) {
complete += 0.5 + Math.floor(Math.random() * 2);
setTimeout(update, 40 + Math.random() * 60);
} else {
this.displayText = nextMessage;
this.currentMessage = nextMessage;
this.isGlitching = true;
this.glitchText();
}
};
this.isGlitching = false;
if (this.frameRequest) {
cancelAnimationFrame(this.frameRequest);
}
update();
}
private glitchText(): void {
if (!this.isGlitching) return;
const probability = Math.random();
if (probability < 0.05) {
// Reduced from 0.2 to 0.05
const scrambledText = this.currentMessage
.split('')
.map(() => (Math.random() > 0.5 ? '0' : '1'))
.join('');
this.displayText = scrambledText;
setTimeout(() => {
this.displayText = this.currentMessage;
}, 25);
} else if (probability < 0.15) {
// Reduced from 0.5 to 0.15
const textArray = this.currentMessage.split('');
for (let i = 0; i < Math.floor(textArray.length * 0.2); i++) {
// Reduced from 0.4 to 0.2
const idx = Math.floor(Math.random() * textArray.length);
textArray[idx] = Math.random() > 0.5 ? '0' : '1';
}
this.displayText = textArray.join('');
setTimeout(() => {
this.displayText = this.currentMessage;
}, 20);
}
const jitterProbability = Math.random();
if (jitterProbability < 0.1) {
// Reduced from 0.5 to 0.1
setTimeout(() => {
const textArray = this.displayText.split('');
for (let i = 0; i < 2; i++) {
// Reduced from 4 to 2 characters
const idx = Math.floor(Math.random() * textArray.length);
if (textArray[idx] === '0' || textArray[idx] === '1') {
textArray[idx] = textArray[idx] === '0' ? '1' : '0';
}
}
this.displayText = textArray.join('');
setTimeout(() => {
this.displayText = this.currentMessage;
}, 15);
}, 15);
}
this.frameRequest = requestAnimationFrame(() => {
setTimeout(() => this.glitchText(), Math.random() * 500); // Increased from 150 to 500
});
}
}