Compare commits
2 Commits
d6411f4dd1
...
aae6f7a25a
| Author | SHA1 | Date | |
|---|---|---|---|
| aae6f7a25a | |||
| eb2e4d7f9e |
@ -16,6 +16,7 @@
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@astrojs/rss": "^4.0.14",
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
|
||||
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ importers:
|
||||
'@astrojs/sitemap':
|
||||
specifier: ^3.6.0
|
||||
version: 3.6.0
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.19
|
||||
version: 0.5.19(tailwindcss@4.1.17)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.17
|
||||
version: 4.1.17(vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
@ -1262,6 +1265,11 @@ packages:
|
||||
resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tailwindcss/typography@0.5.19':
|
||||
resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@tailwindcss/vite@4.1.17':
|
||||
resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==}
|
||||
peerDependencies:
|
||||
@ -2233,6 +2241,10 @@ packages:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@ -2616,6 +2628,9 @@ packages:
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
vfile-location@5.0.3:
|
||||
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
|
||||
|
||||
@ -3730,6 +3745,11 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.17
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.17
|
||||
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@4.1.17)':
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 4.1.17
|
||||
|
||||
'@tailwindcss/vite@4.1.17(vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.1.17
|
||||
@ -5177,6 +5197,11 @@ snapshots:
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
@ -5658,6 +5683,8 @@ snapshots:
|
||||
escalade: 3.2.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vfile-location@5.0.3:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
BIN
public/media/FF_PUFF_GStar_DC_Making-of_v06_H264.mp4
Normal file
BIN
public/media/FF_PUFF_GStar_DC_Making-of_v06_H264.mp4
Normal file
Binary file not shown.
BIN
public/media/FF_PUFF_GStar_DC_v08_4608x3164.mp4
Normal file
BIN
public/media/FF_PUFF_GStar_DC_v08_4608x3164.mp4
Normal file
Binary file not shown.
BIN
public/media/GSTR_01_260_breakdown.mp4
Normal file
BIN
public/media/GSTR_01_260_breakdown.mp4
Normal file
Binary file not shown.
BIN
public/media/GSTR_03_070_v10_breakdown_v01.mp4
Normal file
BIN
public/media/GSTR_03_070_v10_breakdown_v01.mp4
Normal file
Binary file not shown.
BIN
public/media/favicon.JPG
Normal file
BIN
public/media/favicon.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/media/nicholai-closeup-portrait.JPEG
Normal file
BIN
public/media/nicholai-closeup-portrait.JPEG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 MiB |
BIN
public/media/nicholai-medium-portrait.jpg
Normal file
BIN
public/media/nicholai-medium-portrait.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
BIN
public/media/nicholai-wild-portrait.JPEG
Normal file
BIN
public/media/nicholai-wild-portrait.JPEG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 MiB |
@ -12,7 +12,7 @@ const today = new Date();
|
||||
</h2>
|
||||
<div class="flex flex-wrap gap-4 lg:gap-6 mt-12">
|
||||
<a href="mailto:nicholai@nicholai.work" class="btn-primary">nicholai@nicholai.work</a>
|
||||
<a href="tel:7196604281" class="btn-ghost">719 660 4281</a>
|
||||
<a href="/contact" class="btn-ghost">Get in Touch</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
<section id="experience" class="container mx-auto px-6 lg:px-12 py-32">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16">
|
||||
<div class="lg:col-span-4 animate-on-scroll slide-right">
|
||||
<h2 class="text-3xl md:text-4xl font-bold uppercase tracking-tight mb-2 text-stroke">Experience</h2>
|
||||
<!-- Experience heading with scroll-driven fill effect -->
|
||||
<h2 class="text-3xl md:text-4xl font-bold uppercase tracking-tight mb-2 relative">
|
||||
<span class="text-stroke-fill" data-text="Experience">Experience</span>
|
||||
</h2>
|
||||
<h2 class="text-3xl md:text-4xl font-bold uppercase tracking-tight mb-10">History</h2>
|
||||
<p class="text-slate-400 text-base leading-relaxed mb-10 max-w-sm font-light">
|
||||
From founding my own VFX house to supervising global campaigns. I bridge the gap between
|
||||
Running my own VFX studio while taking on select freelance projects. I bridge the gap between
|
||||
creative vision and technical execution.
|
||||
</p>
|
||||
<a href="https://biohazardvfx.com" target="_blank"
|
||||
@ -20,17 +23,17 @@
|
||||
<!-- Vertical line -->
|
||||
<div class="absolute left-0 top-0 bottom-0 w-[1px] bg-gradient-to-b from-brand-accent via-slate-700/50 to-transparent"></div>
|
||||
|
||||
<!-- Item 1 -->
|
||||
<!-- Item 1: Biohazard VFX -->
|
||||
<div class="pl-10 lg:pl-14 mb-20 relative animate-on-scroll slide-up stagger-1">
|
||||
<div class="absolute left-[-5px] top-2 w-3 h-3 bg-brand-dark border-2 border-brand-accent rounded-full"></div>
|
||||
<div class="flex flex-col md:flex-row md:items-baseline gap-3 md:gap-4 mb-5">
|
||||
<h3 class="text-xl md:text-2xl font-bold text-white uppercase tracking-tight">Biohazard VFX</h3>
|
||||
<span class="font-mono text-[10px] text-brand-accent bg-brand-accent/10 px-3 py-1.5 tracking-wide">FOUNDER / VFX SUPERVISOR</span>
|
||||
<span class="font-mono text-xs text-slate-500 md:ml-auto">MAR 2022 — OCT 2025</span>
|
||||
<span class="font-mono text-[10px] text-brand-accent bg-brand-accent/10 px-3 py-1.5 tracking-wide">FOUNDER & OWNER</span>
|
||||
<span class="font-mono text-xs text-slate-500 md:ml-auto">2022 — PRESENT</span>
|
||||
</div>
|
||||
<p class="text-slate-400 mb-8 leading-relaxed font-light">
|
||||
Founded and led a VFX studio specializing in high-end commercial and music video work for
|
||||
Post Malone, ENHYPEN, and Nike. Architected a custom pipeline combining cloud and
|
||||
Founded and continue to lead a VFX studio specializing in high-end commercial and music video work.
|
||||
Delivered projects for Post Malone, ENHYPEN, and Nike. Architected a custom pipeline combining cloud and
|
||||
self-hosted infrastructure.
|
||||
</p>
|
||||
<ul class="space-y-3">
|
||||
@ -47,7 +50,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Item 2 -->
|
||||
<!-- Item 2: Stinkfilms / G-Star -->
|
||||
<div class="pl-10 lg:pl-14 mb-20 relative animate-on-scroll slide-up stagger-2">
|
||||
<div class="absolute left-[-5px] top-2 w-3 h-3 bg-slate-700 rounded-full transition-colors duration-300"></div>
|
||||
<div class="flex flex-col md:flex-row md:items-baseline gap-3 md:gap-4 mb-5">
|
||||
@ -59,7 +62,7 @@
|
||||
Led Biohazard VFX team (60+ artists) alongside director Felix Brady to create a brand film
|
||||
for G-Star Raw.
|
||||
</p>
|
||||
<div class="border border-white/10 bg-white/[0.02] p-6 lg:p-8 backdrop-blur-sm hover:border-brand-accent/30 transition-all duration-500 cursor-pointer group">
|
||||
<a href="/blog/gstar-raw-olympics/" class="block border border-white/10 bg-white/[0.02] p-6 lg:p-8 backdrop-blur-sm hover:border-brand-accent/30 transition-all duration-500 cursor-pointer group">
|
||||
<h4 class="text-sm font-bold uppercase text-white mb-3 flex justify-between items-center tracking-wide">
|
||||
Project: G-Star Raw Olympics Campaign
|
||||
<i data-lucide="arrow-right"
|
||||
@ -68,26 +71,73 @@
|
||||
<p class="text-sm text-slate-400 mb-5 leading-relaxed font-light">
|
||||
Managed full CG environments in Blender/Houdini and integrated AI/ML workflows (Stable Diffusion reference gen, Copycat cleanup).
|
||||
</p>
|
||||
<a href="https://stinkfilms.com"
|
||||
class="text-[10px] font-bold text-brand-accent uppercase tracking-widest hover:text-white transition-colors duration-300">
|
||||
View Case Study
|
||||
</a>
|
||||
</div>
|
||||
<span class="text-[10px] font-bold text-brand-accent uppercase tracking-widest group-hover:text-white transition-colors duration-300">
|
||||
Read Case Study
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Item 3 -->
|
||||
<!-- Item 3: Freelance -->
|
||||
<div class="pl-10 lg:pl-14 relative animate-on-scroll slide-up stagger-3">
|
||||
<div class="absolute left-[-5px] top-2 w-3 h-3 bg-slate-700 rounded-full"></div>
|
||||
<div class="flex flex-col md:flex-row md:items-baseline gap-3 md:gap-4 mb-5">
|
||||
<h3 class="text-xl md:text-2xl font-bold text-white uppercase tracking-tight">Freelance</h3>
|
||||
<span class="font-mono text-[10px] text-slate-400 border border-slate-700 px-3 py-1.5 tracking-wide">2D/3D ARTIST</span>
|
||||
<span class="font-mono text-xs text-slate-500 md:ml-auto">2015 — PRESENT</span>
|
||||
<span class="font-mono text-[10px] text-slate-400 border border-slate-700 px-3 py-1.5 tracking-wide">SELECT PROJECTS</span>
|
||||
<span class="font-mono text-xs text-slate-500 md:ml-auto">ONGOING</span>
|
||||
</div>
|
||||
<p class="text-slate-400 leading-relaxed font-light">
|
||||
Compositor for Abyss Digital and major labels (Atlantic, Interscope). Clients: David
|
||||
Kushner, Opium, Lil Durk, Don Toliver.
|
||||
Taking on select freelance compositing and 3D work alongside studio operations.
|
||||
Previous clients include Abyss Digital and major labels (Atlantic, Interscope) —
|
||||
David Kushner, Opium, Lil Durk, Don Toliver.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* Text stroke fill effect */
|
||||
.text-stroke-fill {
|
||||
position: relative;
|
||||
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.2);
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.text-stroke-fill::before {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
color: var(--color-brand-accent);
|
||||
-webkit-text-stroke: 0;
|
||||
clip-path: inset(0 100% 0 0);
|
||||
transition: clip-path 0.8s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.text-stroke-fill.filled::before {
|
||||
clip-path: inset(0 0 0 0);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Scroll-driven fill effect for Experience heading
|
||||
const experienceHeading = document.querySelector('.text-stroke-fill');
|
||||
|
||||
const fillObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
// Add a slight delay for better effect
|
||||
setTimeout(() => {
|
||||
entry.target.classList.add('filled');
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.5,
|
||||
rootMargin: "0px 0px -100px 0px"
|
||||
});
|
||||
|
||||
if (experienceHeading) {
|
||||
fillObserver.observe(experienceHeading);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -29,11 +29,18 @@
|
||||
Managed full CG environment builds, procedural city generation, and integrated AI-generated
|
||||
normal maps for relighting in Nuke.
|
||||
</p>
|
||||
<a href="https://f.io/7ijf23Wm"
|
||||
class="inline-flex items-center gap-4 text-xs font-bold uppercase tracking-widest text-white hover:text-brand-accent transition-all duration-300 group/link">
|
||||
Watch Making Of
|
||||
<i data-lucide="play-circle" class="w-5 h-5 transition-transform duration-300 group-hover/link:scale-110"></i>
|
||||
</a>
|
||||
<div class="flex flex-wrap items-center gap-6">
|
||||
<a href="/blog/gstar-raw-olympics/"
|
||||
class="inline-flex items-center gap-4 text-xs font-bold uppercase tracking-widest text-white hover:text-brand-accent transition-all duration-300 group/link">
|
||||
Read Case Study
|
||||
<i data-lucide="arrow-right" class="w-4 h-4 transition-transform duration-300 group-hover/link:translate-x-1"></i>
|
||||
</a>
|
||||
<a href="https://f.io/7ijf23Wm" target="_blank" rel="noopener"
|
||||
class="inline-flex items-center gap-4 text-xs font-bold uppercase tracking-widest text-slate-400 hover:text-white transition-all duration-300 group/link">
|
||||
Watch Making Of
|
||||
<i data-lucide="play-circle" class="w-4 h-4 transition-transform duration-300 group-hover/link:scale-110"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:block text-right opacity-80 group-hover:opacity-100 transition-opacity duration-500">
|
||||
|
||||
@ -28,22 +28,49 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero Footer -->
|
||||
<div class="absolute bottom-8 w-full left-0 px-6 lg:px-12 hidden md:flex justify-between items-end opacity-60 animate-on-scroll fade-in stagger-5">
|
||||
<div class="font-mono text-xs text-slate-500 tracking-wide">
|
||||
<div class="absolute bottom-8 w-full left-0 px-6 lg:px-12 hidden md:flex justify-between items-end animate-on-scroll fade-in stagger-5">
|
||||
<div class="font-mono text-xs text-slate-500 tracking-wide opacity-60">
|
||||
<span class="block text-slate-600 mb-1">LOCATION</span>
|
||||
COLORADO SPRINGS, CO<br>
|
||||
<span id="clock" class="text-slate-400">00:00:00</span>
|
||||
</div>
|
||||
<div class="font-mono text-xs text-slate-500 text-right tracking-wide">
|
||||
|
||||
<!-- Scroll Indicator with animation -->
|
||||
<div id="scroll-indicator" class="font-mono text-xs text-slate-500 text-right tracking-wide transition-all duration-500">
|
||||
<span class="block text-slate-600 mb-1">EXPLORE</span>
|
||||
<span class="inline-flex flex-col items-center">
|
||||
SCROLL
|
||||
<span class="block mt-2 w-[1px] h-6 bg-gradient-to-b from-slate-500 to-transparent"></span>
|
||||
<span class="scroll-arrow block mt-2 w-[1px] h-8 bg-gradient-to-b from-brand-accent to-transparent"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* Scroll arrow bounce animation */
|
||||
.scroll-arrow {
|
||||
animation: scrollBounce 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes scrollBounce {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(8px);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fade out on scroll */
|
||||
#scroll-indicator.scrolled {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function updateClock() {
|
||||
const clock = document.getElementById('clock');
|
||||
@ -55,4 +82,28 @@
|
||||
}
|
||||
setInterval(updateClock, 1000);
|
||||
updateClock();
|
||||
|
||||
// Scroll-driven fade for scroll indicator
|
||||
const scrollIndicator = document.getElementById('scroll-indicator');
|
||||
|
||||
function handleScroll() {
|
||||
if (scrollIndicator) {
|
||||
const scrollY = window.scrollY;
|
||||
// Start fading at 50px, fully hidden at 200px
|
||||
const opacity = Math.max(0, 1 - (scrollY / 150));
|
||||
const translateY = Math.min(20, scrollY / 10);
|
||||
|
||||
scrollIndicator.style.opacity = opacity.toString();
|
||||
scrollIndicator.style.transform = `translateY(${translateY}px)`;
|
||||
|
||||
if (scrollY > 50) {
|
||||
scrollIndicator.classList.add('scrolled');
|
||||
} else {
|
||||
scrollIndicator.classList.remove('scrolled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
handleScroll(); // Initial check
|
||||
</script>
|
||||
|
||||
49
src/content/blog/gstar-raw-olympics.md
Normal file
49
src/content/blog/gstar-raw-olympics.md
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: 'G-Star Raw Olympics Campaign'
|
||||
description: 'A deep dive into the VFX supervision and technical pipeline behind the G-Star Raw Olympics brand film, created in collaboration with Stinkfilms and director Felix Brady.'
|
||||
pubDate: 'Aug 15 2024'
|
||||
heroImage: '../../assets/blog-placeholder-1.jpg'
|
||||
---
|
||||
|
||||
In summer 2024, Biohazard VFX partnered with Stinkfilms and director Felix Brady to create a visually striking brand film for G-Star Raw's Olympics campaign. This project pushed our team of 60+ artists to deliver high-end CG environments while pioneering new AI/ML integration workflows.
|
||||
|
||||
## The Challenge
|
||||
|
||||
The creative brief called for expansive cityscapes and environments that would feel both futuristic and grounded in reality. The timeline was aggressive, and the scope was ambitious—exactly the kind of project we thrive on.
|
||||
|
||||
## Technical Approach
|
||||
|
||||
### Full CG Environment Pipeline
|
||||
|
||||
We built our environments entirely in Blender and Houdini, leveraging procedural generation for the city layouts. This allowed us to iterate quickly on creative direction while maintaining the flexibility to make large-scale changes late in production.
|
||||
|
||||
Key technical achievements:
|
||||
- **Procedural city generation** using Houdini's node-based workflows
|
||||
- **USD-based asset management** for seamless handoff between departments
|
||||
- **Karma rendering** for final output with deep compositing support
|
||||
|
||||
### AI/ML Integration
|
||||
|
||||
One of the most innovative aspects of this project was our integration of AI tools into a production VFX pipeline:
|
||||
|
||||
- **Stable Diffusion reference generation** for rapid concept exploration and creative alignment with the director
|
||||
- **Copycat cleanup workflows** for efficiently handling repetitive cleanup tasks
|
||||
- **AI-generated normal maps** for relighting elements in Nuke post-composite
|
||||
|
||||
The key was treating AI output as a starting point, not a final deliverable. Every AI-generated asset went through our QA pipeline and was refined by artists to meet production standards.
|
||||
|
||||
## The Team
|
||||
|
||||
Managing 60+ artists across multiple time zones required robust communication and pipeline infrastructure. We developed custom tools for:
|
||||
- Real-time progress tracking
|
||||
- Automated daily builds
|
||||
- Version control and asset management
|
||||
|
||||
## Results
|
||||
|
||||
The final film delivered on time and exceeded client expectations. The combination of traditional VFX craft with cutting-edge AI tools allowed us to achieve a level of visual complexity that would have been prohibitively expensive using traditional methods alone.
|
||||
|
||||
---
|
||||
|
||||
*This project exemplifies the direction we're taking at Biohazard VFX: embracing new technology while never compromising on quality or artistic vision.*
|
||||
|
||||
@ -11,27 +11,41 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||
|
||||
<BaseLayout title={title} description={description}>
|
||||
<article class="container mx-auto px-6 lg:px-12 max-w-4xl">
|
||||
<div class="mb-12">
|
||||
<div class="mb-6">
|
||||
{heroImage && <Image width={1020} height={510} src={heroImage} alt="" class="w-full h-auto rounded-none border border-white/10" />}
|
||||
<!-- Back Navigation -->
|
||||
<a href="/blog" class="inline-flex items-center gap-3 text-xs font-semibold uppercase tracking-widest text-slate-500 hover:text-white transition-colors duration-300 mb-12 group">
|
||||
<span class="w-8 h-[1px] bg-slate-600 group-hover:bg-brand-accent group-hover:w-12 transition-all duration-300"></span>
|
||||
Back to Blog
|
||||
</a>
|
||||
|
||||
<div class="mb-12 animate-on-scroll slide-up">
|
||||
<div class="mb-8">
|
||||
{heroImage && <Image width={1020} height={510} src={heroImage} alt="" class="w-full h-auto border border-white/10" />}
|
||||
</div>
|
||||
<div class="border-b border-white/10 pb-8 mb-8">
|
||||
<div class="flex items-center gap-4 text-xs font-mono text-slate-500 uppercase tracking-widest mb-4">
|
||||
<div class="border-b border-white/10 pb-10 mb-10">
|
||||
<div class="flex items-center gap-4 text-xs font-mono text-slate-500 uppercase tracking-widest mb-6">
|
||||
<FormattedDate date={pubDate} />
|
||||
{
|
||||
updatedDate && (
|
||||
<div class="italic">
|
||||
<span class="text-slate-600">
|
||||
(Updated: <FormattedDate date={updatedDate} />)
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-white uppercase leading-tight mb-4">{title}</h1>
|
||||
<p class="text-xl text-slate-400 leading-relaxed">{description}</p>
|
||||
<h1 class="text-3xl md:text-5xl lg:text-6xl font-bold text-white uppercase leading-tight tracking-tight mb-6">{title}</h1>
|
||||
<p class="text-lg lg:text-xl text-slate-400 leading-relaxed font-light">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prose prose-invert prose-lg max-w-none text-slate-300 prose-headings:text-white prose-headings:uppercase prose-headings:font-bold prose-a:text-brand-accent prose-a:no-underline hover:prose-a:underline prose-strong:text-white prose-code:text-brand-accent prose-code:bg-brand-accent/10 prose-code:px-1 prose-code:rounded-sm prose-pre:bg-brand-panel prose-pre:border prose-pre:border-white/10">
|
||||
<div class="prose-custom animate-on-scroll slide-up stagger-1">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<!-- Bottom Navigation -->
|
||||
<div class="mt-20 pt-10 border-t border-white/10">
|
||||
<a href="/blog" class="inline-flex items-center gap-3 text-xs font-semibold uppercase tracking-widest text-slate-500 hover:text-white transition-colors duration-300 group">
|
||||
<span class="w-8 h-[1px] bg-slate-600 group-hover:bg-brand-accent group-hover:w-12 transition-all duration-300"></span>
|
||||
Back to All Posts
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
</BaseLayout>
|
||||
|
||||
@ -12,6 +12,12 @@ const posts = (await getCollection('blog')).sort(
|
||||
|
||||
<BaseLayout title={SITE_TITLE} description={SITE_DESCRIPTION}>
|
||||
<section class="container mx-auto px-6 lg:px-12">
|
||||
<!-- Back Navigation -->
|
||||
<a href="/" class="inline-flex items-center gap-3 text-xs font-semibold uppercase tracking-widest text-slate-500 hover:text-white transition-colors duration-300 mb-12 group">
|
||||
<span class="w-8 h-[1px] bg-slate-600 group-hover:bg-brand-accent group-hover:w-12 transition-all duration-300"></span>
|
||||
Back to Home
|
||||
</a>
|
||||
|
||||
<div class="mb-20 animate-on-scroll slide-up">
|
||||
<h1 class="text-5xl md:text-7xl lg:text-8xl font-bold uppercase text-white mb-5 tracking-tighter">Blog</h1>
|
||||
<p class="text-slate-500 font-mono text-sm tracking-wide">/// THOUGHTS & PROCESS</p>
|
||||
|
||||
@ -80,18 +80,9 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
||||
<div class="lg:col-span-5 space-y-12 animate-on-scroll slide-left stagger-2">
|
||||
<div>
|
||||
<h3 class="text-xs font-bold uppercase tracking-widest text-slate-500 mb-6">Contact Info</h3>
|
||||
<ul class="space-y-4">
|
||||
<li>
|
||||
<a href="mailto:nicholai@nicholai.work" class="text-lg lg:text-xl text-white hover:text-brand-accent transition-colors duration-300 font-mono block">
|
||||
nicholai@nicholai.work
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="tel:7196604281" class="text-lg lg:text-xl text-white hover:text-brand-accent transition-colors duration-300 font-mono block">
|
||||
719 660 4281
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a href="mailto:nicholai@nicholai.work" class="text-lg lg:text-xl text-white hover:text-brand-accent transition-colors duration-300 font-mono block">
|
||||
nicholai@nicholai.work
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@theme {
|
||||
--color-brand-dark: #0B0D11;
|
||||
@ -300,3 +301,148 @@ a {
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
/* ===== PROSE / MARKDOWN STYLES ===== */
|
||||
.prose-custom {
|
||||
color: #94A3B8;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.prose-custom h2 {
|
||||
color: #ffffff;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: -0.025em;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 1.25rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.prose-custom h3 {
|
||||
color: #ffffff;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: -0.015em;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose-custom h4 {
|
||||
color: #ffffff;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.prose-custom p {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.prose-custom a {
|
||||
color: var(--color-brand-accent);
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.prose-custom a:hover {
|
||||
color: #ffffff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.prose-custom strong {
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose-custom em {
|
||||
color: #CBD5E1;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.prose-custom ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.prose-custom ul li {
|
||||
position: relative;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.prose-custom ul li::before {
|
||||
content: "▹";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--color-brand-accent);
|
||||
}
|
||||
|
||||
.prose-custom ol {
|
||||
list-style: decimal;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.prose-custom ol li {
|
||||
margin-bottom: 0.75rem;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.prose-custom ol li::marker {
|
||||
color: var(--color-brand-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose-custom blockquote {
|
||||
border-left: 3px solid var(--color-brand-accent);
|
||||
padding-left: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
font-style: italic;
|
||||
color: #CBD5E1;
|
||||
}
|
||||
|
||||
.prose-custom code {
|
||||
color: var(--color-brand-accent);
|
||||
background-color: rgba(255, 77, 0, 0.1);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 2px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.prose-custom pre {
|
||||
background-color: var(--color-brand-panel);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.prose-custom pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
color: #CBD5E1;
|
||||
}
|
||||
|
||||
.prose-custom hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.2) 20%,
|
||||
rgba(255, 255, 255, 0.2) 80%,
|
||||
transparent
|
||||
);
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.prose-custom img {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user