biohazard-web-old/index.html
2025-10-02 16:01:12 -06:00

312 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-current="home">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Biohazard VFX | VFX Studio &amp; Post-Production</title>
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png" />
<!-- SEO Meta -->
<meta name="description" content="Biohazard VFX is a global visual-effects studio delivering world-class VFX supervision, 3D animation, and end-to-end post-production." />
<!-- canonical -->
<link rel="canonical" href="https://biohazardvfx.com/" />
<!-- Preload critical fonts -->
<link rel="preload" href="fonts/BebasNeue-Regular.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="fonts/Space_Mono/SpaceMono-Regular.ttf" as="font" type="font/ttf" crossorigin />
<meta name="robots" content="index, follow" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:title" content="Biohazard VFX — Visual Effects Studio" />
<meta property="og:description" content="Global visual-effects & post-production studio delivering world-class VFX supervision, 3D animation, and finishing." />
<meta property="og:image" content="/images/Splash.jpg" />
<meta property="og:url" content="https://biohazardvfx.com/" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Biohazard VFX — Visual Effects Studio" />
<meta name="twitter:description" content="Global visual-effects & post-production studio delivering world-class VFX supervision, 3D animation, and finishing." />
<meta name="twitter:image" content="/images/Splash.jpg" />
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Biohazard VFX",
"url": "https://biohazardvfx.com/",
"logo": "https://biohazardvfx.com/images/favicon-32x32.png",
"contactPoint": [{
"@type": "ContactPoint",
"email": "contact@biohazardvfx.com",
"contactType": "customer service"
}],
"sameAs": [
"https://www.instagram.com/nicholai.exe/",
"https://www.instagram.com/davaneh/",
"https://www.instagram.com/nuke_fx/"
]
}
</script>
<!-- Main stylesheet -->
<link rel="stylesheet" href="css/styles.css" />
<link rel="stylesheet" href="css/home.css" />
<!-- GLOBAL FONT-SIZE CONTROLS ---------------------->
<style id="global-font-scale">
/*
Adjust --font-scale below to make type bigger or smaller everywhere.
1 = 100% (default). 1.1 = +10%. 0.9 = 10%, etc.
*/
:root {
--font-scale: 1.0;
}
html { font-size: calc(16px * var(--font-scale)); }
</style>
<!-- END FONT-SIZE CONTROLS -->
<style>
.content-block, .section {
max-width: 1100px;
margin: 0 auto 4.5rem auto;
padding: 8vh var(--gutter-x) 6vh;
background: none;
border-radius: 0.7em;
box-sizing: border-box;
}
main.grid {
max-width: 2000px;
margin-left: auto;
margin-right: auto;
gap: 22px;
}
@media (max-width: 900px) {
.content-block, .section {
padding: 5vh 16px 3vh;
max-width: 98vw;
}
main.grid {
max-width: 98vw;
gap: 14px;
}
}
@media (max-width: 600px) {
.content-block, .section {
padding: 3vh 6px 2vh;
max-width: 100vw;
}
main.grid {
max-width: 100vw;
gap: 8px;
}
}
#projects.grid {
margin-bottom: 4.5rem;
}
#about.content-block {
margin-top: 4.5rem;
max-width: 2000px;
margin-left: auto;
margin-right: auto;
}
#team.content-block {
margin-top: 4.5rem;
max-width: 2000px;
margin-left: auto;
margin-right: auto;
}
#crew.content-block {
margin-top: 4.5rem;
max-width: 2000px;
margin-left: auto;
margin-right: auto;
}
#pipeline.section {
margin-bottom: 4.5rem;
max-width: 2000px;
margin-left: auto;
margin-right: auto;
}
footer {
margin-top: 2.5rem;
padding-bottom: 1.5rem;
}
</style>
</head>
<body>
<!-- =======================================================
NAV
======================================================= -->
<div id="nav-placeholder"></div>
<!-- HERO SECTION -->
<section id="hero" class="hero">
<video src="videos/reel.mp4" autoplay muted loop playsinline preload="metadata"></video>
</section>
<!-- =======================================================
ABOUT
======================================================= -->
<section id="about" class="content-block" data-speed="0.15">
<div class="about-content">
<!-- Content dynamically injected -->
</div>
</section>
<!-- =======================================================
PROJECT GRID (populated dynamically from /projects)
======================================================= -->
<main id="projects" class="grid" data-speed="0.1"></main>
<!-- =======================================================
TEAM SECTION (portraits)
======================================================= -->
<section id="team" class="content-block" data-speed="0.12">
<h2>Meet The Founders</h2>
<div class="team-container">
<a class="portrait" href="https://www.instagram.com/nicholai.exe/" target="_blank" aria-label="Nicholai Vogel Instagram">
<img src="images/nicholai.jpg" alt="Nicholai Vogel">
<h3>Nicholai Vogel</h3>
<p>Founder & CEO<br>VFX & CG Supervisor<br><span style="opacity:.7;font-size:.95em">"I just work here."</span></p>
</a>
<a class="portrait" href="https://www.instagram.com/davaneh/" target="_blank" aria-label="Davane Instagram">
<img src="images/davane.jpg" alt="Davane">
<h3>DAVANÉ</h3>
<p>Co-Founder & Executive Producer<br>VFX Supervisor<br><span style="opacity:.7;font-size:.95em">"The Executive"</span></p>
</a>
<a class="portrait" href="https://www.instagram.com/nuke_fx/" target="_blank" aria-label="Parth Gupta Instagram">
<img src="images/parth.jpg" alt="Parth Gupta">
<h3>Parth Gupta</h3>
<p>Co-Founder & Executive Producer<br>Comp Lead<br><span style="opacity:.7;font-size:.95em">"Hates Matchmove"</span></p>
</a>
</div>
</section>
<!-- =======================================================
CREW COPY SECTION (text injected from written/crew.txt)
======================================================= -->
<section id="crew" class="content-block" data-speed="0.14">
<div class="crew-content"><!-- Content dynamically injected --></div>
</section>
<!-- =======================================================
Pipeline Section
=======================================================
<section id="pipeline" class="section">
<h2>PIPELINE</h2>
<div class="pipeline-content" id="pipeline-content">
</div>
</section> -->
<div class="contact-info" style="margin-top:2em;text-align:center;font-size:1em;opacity:.7;">
<p>We usually reply within 24 hours.<br>Email: <a href="mailto:contact@biohazardvfx.com">contact@biohazardvfx.com</a></p>
</div>
<!-- Main JS bundle (handles lazy-loading + data fetch) -->
<script src="js/main.js" defer></script>
<script src="js/common.js" defer></script>
<script src="js/ui.js" defer></script>
<script src="js/home.js" defer></script>
<!-- =======================================================
Social Links
======================================================= -->
<div id="socials-placeholder"></div>
<!-- =======================================================
COPYRIGHT
(static content, copyright notice)
======================================================= -->
<footer>
<p>© 2025 Biohazard VFX. All Rights Reserved.</p>
</footer>
<script>
// Inject nav fragment
fetch('fragments/nav.html')
.then(r => r.text())
.then(html => {
document.getElementById('nav-placeholder').outerHTML = html;
});
// Inject socials fragment
fetch('fragments/socials.html')
.then(r => r.text())
.then(html => {
document.getElementById('socials-placeholder').outerHTML = html;
});
// Inject pipeline blurb
fetch('written/pipeline.txt')
.then(r => r.text())
.then(txt => {
document.getElementById('pipeline-content').innerHTML = `<p>${txt}</p>`;
});
// 2. Smooth scroll navigation for anchor links
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
const targetId = this.getAttribute('href').slice(1);
const target = document.getElementById(targetId);
if(target) {
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
});
});
// 10. Lazy loading for all images and iframes
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('img, iframe').forEach(el => {
if(!el.hasAttribute('loading')) el.setAttribute('loading', 'lazy');
});
});
// 9. Accessibility: Add ARIA labels to nav links
document.querySelectorAll('header.nav nav a').forEach(link => {
if(!link.hasAttribute('aria-label')) {
link.setAttribute('aria-label', link.textContent.trim());
}
});
// 11. Parallax video effect
document.addEventListener('DOMContentLoaded',()=>{
const hero=document.getElementById('hero');
const about=document.getElementById('about');
const video=hero?.querySelector('video');
if(!hero||!about||!video) return;
const update=()=>{
const scrollY=window.scrollY;
const viewportHeight=window.innerHeight;
const aboutRect=about.getBoundingClientRect();
const aboutTop=aboutRect.top;
// Gradually fade IN gradient as we scroll: 0 when at top, 1 once About approaches hero top
const gradientOpacity = Math.max(0, Math.min(1, (viewportHeight - aboutTop) / (viewportHeight * .0125)));
hero.style.setProperty('--gradient-opacity', gradientOpacity);
// Allow the About block to slide upward and sit over the video. We let the margin become
// slightly negative for an overlapping effect once the user scrolls further.
const aboutPadding=15-(scrollY*0.03); // rem units can go negative for overlap
about.style.marginTop=aboutPadding+'rem';
// Move video box smoothly - no position switching
const videoOffset=Math.max(0,scrollY-viewportHeight/2);
video.style.transform=`translateY(${videoOffset}px)`;
};
update();
window.addEventListener('scroll',update,{passive:true});
window.addEventListener('resize',update,{passive:true});
});
</script>
</body>
</html>