mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 02:53:51 +00:00
hero bugfixes/improvements
This commit is contained in:
@@ -370,16 +370,6 @@ function addComeback(tw: TypewriterInstance, onRetire: () => void, completions:
|
|||||||
`<span class="text-yellow">until they're the only way out</span>`
|
`<span class="text-yellow">until they're the only way out</span>`
|
||||||
).pauseFor(4000).deleteAll();
|
).pauseFor(4000).deleteAll();
|
||||||
|
|
||||||
// --- Visitor count ---
|
|
||||||
|
|
||||||
if (completions !== null && completions > 0) {
|
|
||||||
tw.typeString(
|
|
||||||
`<span>You're visitor </span>` +
|
|
||||||
`<span class="text-yellow">#${completions.toLocaleString()}</span>${BR}` +
|
|
||||||
`<span class="text-aqua">to make it this far</span>`
|
|
||||||
).pauseFor(5000).deleteAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Done for real ---
|
// --- Done for real ---
|
||||||
|
|
||||||
addDots(tw, 1000, 4000);
|
addDots(tw, 1000, 4000);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Canvas } from "@react-three/fiber";
|
|||||||
import VoidTypewriter from "./typewriter";
|
import VoidTypewriter from "./typewriter";
|
||||||
import VoidWater from "./scenes/void-water";
|
import VoidWater from "./scenes/void-water";
|
||||||
|
|
||||||
|
// Canvas glitch: transforms + filters (physical shake + color corruption)
|
||||||
|
// Text glitch: filters only (color corruption, no position shift)
|
||||||
const GLITCH_CSS = `
|
const GLITCH_CSS = `
|
||||||
.void-glitch-subtle {
|
.void-glitch-subtle {
|
||||||
animation: void-glitch-subtle 2s ease-in-out infinite;
|
animation: void-glitch-subtle 2s ease-in-out infinite;
|
||||||
@@ -13,6 +15,15 @@ const GLITCH_CSS = `
|
|||||||
.void-glitch-dissolve {
|
.void-glitch-dissolve {
|
||||||
animation: void-glitch-dissolve 2s ease-in forwards;
|
animation: void-glitch-dissolve 2s ease-in forwards;
|
||||||
}
|
}
|
||||||
|
.void-text-glitch-subtle {
|
||||||
|
animation: void-text-glitch-subtle 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.void-text-glitch-intense {
|
||||||
|
animation: void-text-glitch-intense 1.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.void-text-glitch-dissolve {
|
||||||
|
animation: void-text-glitch-dissolve 2s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes void-glitch-subtle {
|
@keyframes void-glitch-subtle {
|
||||||
0%, 100% { transform: none; filter: none; }
|
0%, 100% { transform: none; filter: none; }
|
||||||
@@ -29,6 +40,15 @@ const GLITCH_CSS = `
|
|||||||
85% { transform: translateX(-1px) skewY(0.1deg); }
|
85% { transform: translateX(-1px) skewY(0.1deg); }
|
||||||
87% { transform: none; }
|
87% { transform: none; }
|
||||||
}
|
}
|
||||||
|
@keyframes void-text-glitch-subtle {
|
||||||
|
0%, 100% { filter: none; }
|
||||||
|
3% { filter: hue-rotate(15deg); }
|
||||||
|
6% { filter: none; }
|
||||||
|
30% { filter: saturate(1.5); }
|
||||||
|
32% { filter: none; }
|
||||||
|
70% { filter: hue-rotate(-10deg); }
|
||||||
|
72% { filter: none; }
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes void-glitch-intense {
|
@keyframes void-glitch-intense {
|
||||||
0%, 100% { transform: none; filter: none; }
|
0%, 100% { transform: none; filter: none; }
|
||||||
@@ -48,6 +68,21 @@ const GLITCH_CSS = `
|
|||||||
85% { transform: skewX(-1deg) translateX(2px) translateY(-1px); filter: saturate(5); }
|
85% { transform: skewX(-1deg) translateX(2px) translateY(-1px); filter: saturate(5); }
|
||||||
88% { transform: none; filter: none; }
|
88% { transform: none; filter: none; }
|
||||||
}
|
}
|
||||||
|
@keyframes void-text-glitch-intense {
|
||||||
|
0%, 100% { filter: none; }
|
||||||
|
2% { filter: hue-rotate(60deg) saturate(3); }
|
||||||
|
5% { filter: none; }
|
||||||
|
12% { filter: hue-rotate(-90deg); }
|
||||||
|
15% { filter: none; }
|
||||||
|
25% { filter: saturate(4); }
|
||||||
|
28% { filter: none; }
|
||||||
|
40% { filter: hue-rotate(120deg) saturate(2); }
|
||||||
|
42% { filter: none; }
|
||||||
|
70% { filter: hue-rotate(-45deg) saturate(3); }
|
||||||
|
73% { filter: none; }
|
||||||
|
85% { filter: saturate(5); }
|
||||||
|
88% { filter: none; }
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes void-glitch-dissolve {
|
@keyframes void-glitch-dissolve {
|
||||||
0% { transform: none; filter: none; opacity: 1; }
|
0% { transform: none; filter: none; opacity: 1; }
|
||||||
@@ -65,6 +100,18 @@ const GLITCH_CSS = `
|
|||||||
80% { transform: translateX(-2px); opacity: 0.1; }
|
80% { transform: translateX(-2px); opacity: 0.1; }
|
||||||
100% { transform: none; filter: none; opacity: 0; }
|
100% { transform: none; filter: none; opacity: 0; }
|
||||||
}
|
}
|
||||||
|
@keyframes void-text-glitch-dissolve {
|
||||||
|
0% { filter: none; opacity: 1; }
|
||||||
|
3% { filter: hue-rotate(90deg) saturate(4); }
|
||||||
|
10% { filter: hue-rotate(-120deg) saturate(3); opacity: 0.9; }
|
||||||
|
20% { filter: hue-rotate(180deg) saturate(5); opacity: 0.8; }
|
||||||
|
30% { filter: saturate(6) hue-rotate(60deg); opacity: 0.7; }
|
||||||
|
40% { filter: hue-rotate(-90deg); opacity: 0.55; }
|
||||||
|
50% { filter: saturate(3); opacity: 0.4; }
|
||||||
|
60% { filter: hue-rotate(150deg); opacity: 0.3; }
|
||||||
|
80% { filter: none; opacity: 0.1; }
|
||||||
|
100% { filter: none; opacity: 0; }
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function getCorruption(segment: number): number {
|
function getCorruption(segment: number): number {
|
||||||
@@ -73,7 +120,7 @@ function getCorruption(segment: number): number {
|
|||||||
if (segment === 9) return 0.08;
|
if (segment === 9) return 0.08;
|
||||||
if (segment === 10) return 0.1;
|
if (segment === 10) return 0.1;
|
||||||
if (segment === 11) return 0.13;
|
if (segment === 11) return 0.13;
|
||||||
if (segment === 12) return 0.1; // "anyway" — dips
|
if (segment === 12) return 0.1;
|
||||||
if (segment === 13) return 0.3;
|
if (segment === 13) return 0.3;
|
||||||
if (segment === 14) return 0.6;
|
if (segment === 14) return 0.6;
|
||||||
if (segment === 15) return 0.75;
|
if (segment === 15) return 0.75;
|
||||||
@@ -81,13 +128,20 @@ function getCorruption(segment: number): number {
|
|||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGlitchClass(segment: number, dissolving: boolean): string {
|
function getCanvasGlitch(segment: number, dissolving: boolean): string {
|
||||||
if (dissolving) return "void-glitch-dissolve";
|
if (dissolving) return "void-glitch-dissolve";
|
||||||
if (segment < 8) return "";
|
if (segment < 8) return "";
|
||||||
if (segment <= 14) return "void-glitch-subtle";
|
if (segment <= 14) return "void-glitch-subtle";
|
||||||
return "void-glitch-intense";
|
return "void-glitch-intense";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTextGlitch(segment: number, dissolving: boolean): string {
|
||||||
|
if (dissolving) return "void-text-glitch-dissolve";
|
||||||
|
if (segment < 8) return "";
|
||||||
|
if (segment <= 14) return "void-text-glitch-subtle";
|
||||||
|
return "void-text-glitch-intense";
|
||||||
|
}
|
||||||
|
|
||||||
interface VoidExperienceProps {
|
interface VoidExperienceProps {
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
@@ -97,16 +151,28 @@ export default function VoidExperience({ token }: VoidExperienceProps) {
|
|||||||
const [visitCount, setVisitCount] = useState<number | null>(null);
|
const [visitCount, setVisitCount] = useState<number | null>(null);
|
||||||
const [dissolving, setDissolving] = useState(false);
|
const [dissolving, setDissolving] = useState(false);
|
||||||
|
|
||||||
// Inject CSS once
|
// Inject CSS + hide cursor + force fullscreen feel on mobile
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
style.textContent = GLITCH_CSS;
|
style.textContent = GLITCH_CSS;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
// Hide cursor during void experience
|
|
||||||
document.body.style.cursor = "none";
|
document.body.style.cursor = "none";
|
||||||
|
|
||||||
|
// Push mobile tab bar off-screen by making the page taller than viewport
|
||||||
|
const meta = document.querySelector('meta[name="viewport"]');
|
||||||
|
const origContent = meta?.getAttribute("content") || "";
|
||||||
|
meta?.setAttribute("content", "width=device-width, initial-scale=1, interactive-widget=resizes-content");
|
||||||
|
document.documentElement.style.overflow = "hidden";
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
// Scroll down slightly to trigger mobile browsers hiding the tab bar
|
||||||
|
window.scrollTo(0, 1);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
style.remove();
|
style.remove();
|
||||||
document.body.style.cursor = "";
|
document.body.style.cursor = "";
|
||||||
|
document.documentElement.style.overflow = "";
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
if (meta) meta.setAttribute("content", origContent);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -144,12 +210,11 @@ export default function VoidExperience({ token }: VoidExperienceProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const corruption = getCorruption(activeSegment);
|
const corruption = getCorruption(activeSegment);
|
||||||
const glitchClass = getGlitchClass(activeSegment, dissolving);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black">
|
<div className="fixed inset-0 bg-black" style={{ height: "100dvh" }}>
|
||||||
{/* 3D Canvas — filter applied directly to this element, not a parent */}
|
{/* 3D Canvas — full glitch (transforms + filters) */}
|
||||||
<div className={`fixed inset-0 z-[10] ${glitchClass}`}>
|
<div className={`fixed inset-0 z-[10] ${getCanvasGlitch(activeSegment, dissolving)}`}>
|
||||||
<Canvas
|
<Canvas
|
||||||
camera={{ position: [0, 0, 8], fov: 60 }}
|
camera={{ position: [0, 0, 8], fov: 60 }}
|
||||||
dpr={[1, 1.5]}
|
dpr={[1, 1.5]}
|
||||||
@@ -160,9 +225,9 @@ export default function VoidExperience({ token }: VoidExperienceProps) {
|
|||||||
</Canvas>
|
</Canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Typewriter — same glitch class applied directly */}
|
{/* Typewriter — filter-only glitch (no transform shift) */}
|
||||||
{visitCount !== null && (
|
{visitCount !== null && (
|
||||||
<div className={glitchClass}>
|
<div className={getTextGlitch(activeSegment, dissolving)}>
|
||||||
<VoidTypewriter
|
<VoidTypewriter
|
||||||
startSegment={0}
|
startSegment={0}
|
||||||
onPhaseComplete={handlePhaseComplete}
|
onPhaseComplete={handlePhaseComplete}
|
||||||
|
|||||||
Reference in New Issue
Block a user