From ffb140ac7fd902d05cbd04dc1637688b51044afc Mon Sep 17 00:00:00 2001 From: Nicholai Date: Mon, 8 Dec 2025 01:29:03 -0700 Subject: [PATCH] Add open-source VFX pipeline guide and enhance site structure - Introduced a comprehensive guide on building a production-ready VFX pipeline using open-source tools, detailing cost breakdowns and workflows. - Added new sections for experience, featured projects, skills, and contact information, enhancing the overall site structure and user navigation. - Updated components to utilize dynamic content from new markdown files, improving maintainability and scalability of the site. - Enhanced the contact page with structured data for better user interaction and accessibility. --- src/components/sections/Experience.astro | 241 +++++++++--------- src/components/sections/FeaturedProject.astro | 58 +++-- src/components/sections/Hero.astro | 22 +- src/components/sections/Skills.astro | 123 ++++----- src/content.config.ts | 88 ++++++- src/content/pages/contact.mdx | 33 +++ src/content/sections/experience.mdx | 43 ++++ src/content/sections/featured-project.mdx | 21 ++ src/content/sections/hero.mdx | 9 + src/content/sections/skills.mdx | 23 ++ src/pages/contact.astro | 87 +++---- src/pages/index.astro | 53 +++- 12 files changed, 526 insertions(+), 275 deletions(-) create mode 100644 src/content/pages/contact.mdx create mode 100644 src/content/sections/experience.mdx create mode 100644 src/content/sections/featured-project.mdx create mode 100644 src/content/sections/hero.mdx create mode 100644 src/content/sections/skills.mdx diff --git a/src/components/sections/Experience.astro b/src/components/sections/Experience.astro index ecad7de..1060761 100644 --- a/src/components/sections/Experience.astro +++ b/src/components/sections/Experience.astro @@ -1,4 +1,29 @@ --- +interface Props { + sectionTitle: string; + sectionSubtitle: string; + sectionLabel: string; + description: string; + entries: Array<{ + systemId: string; + status: string; + dates: string; + company: string; + role: string; + tags?: string[]; + description: string; + achievements?: Array<{ + label: string; + text: string; + }>; + link?: { + url: string; + text: string; + }; + }>; +} + +const { sectionTitle, sectionSubtitle, sectionLabel, description, entries } = Astro.props; ---
@@ -6,136 +31,122 @@

- Experience - History -

+ {sectionTitle} + {sectionSubtitle}
-
/// Career Timeline
+
{sectionLabel}

- Bridging creative vision with technical execution. From running a dedicated VFX studio to high-end freelance supervision. + {description}

+ + {entries[0] && (() => { + const entry = entries[0]; + return ( +
+ +
+
- -
- -
-
- - -
-
- SYS.01 /// ACTIVE -
-
- 2022 — PRESENT -
- -
-
-

Biohazard VFX

- Founder & Owner - -
- Studio Lead - Pipeline Arch -
-
-
-

- Founded and 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. -

- -
-
-

Key Achievement

-

Designed 7-plate reconciliation workflows for ENHYPEN (projection mapping live action onto CAD).

+ +
+
+ {entry.systemId} /// {entry.status} +
-
-

System Impact

-

Developed QA systems for AI-generated assets, transforming mid-tier output into production-ready deliverables.

+ {entry.dates} +
+ +
+
+

{entry.company}

+ {entry.role} + + {entry.tags && entry.tags.length > 0 && ( +
+ {entry.tags.map((tag) => ( + {tag} + ))} +
+ )} +
+
+

+ {entry.description} +

+ + {entry.achievements && entry.achievements.length > 0 && ( +
+ {entry.achievements.map((achievement) => ( +
+

{achievement.label}

+

{achievement.text}

+
+ ))} +
+ )} + + {entry.link && ( + + )}
- -
+ ); + })()} + + + {entries.length > 1 && ( +
+ {entries.slice(1).map((entry, index) => ( +
+ +
+ + +
+
+ {entry.systemId} /// {entry.status} +
+ {entry.dates} +
+ +
+
+

{entry.company}

+ {entry.role} +
+

+ {entry.description} +

+ {entry.link && ( + + )} + {entry.tags && entry.tags.length > 0 && ( +
+ {entry.tags.map((tag) => ( + {tag} + ))} +
+ )} +
+
+ ))}
-
- - -
- - -
- -
- - -
-
- SYS.02 /// ARCHIVED -
- SUMMER 2024 -
- -
-
-

Stinkfilms

- VFX Supervisor -
-

- Led Biohazard VFX team (60+ artists) alongside director Felix Brady to create a brand film for G-Star Raw. - Managed full CG environments in Blender/Houdini. -

- -
-
- - -
- -
- - -
-
- SYS.03 /// DAEMON -
- 2016 — PRESENT -
- -
-
-

Freelance

- Senior Compositor -
-

- Taking on select freelance compositing and 3D work alongside studio operations. - Clients include Abyss Digital, Atlantic, Interscope. -

-
- Nuke - Flame -
-
-
- -
- + )}
diff --git a/src/components/sections/FeaturedProject.astro b/src/components/sections/FeaturedProject.astro index b003b95..d809f68 100644 --- a/src/components/sections/FeaturedProject.astro +++ b/src/components/sections/FeaturedProject.astro @@ -1,8 +1,25 @@ --- +interface Props { + role: string; + client: string; + year: string; + region: string; + projectTitle: string; + projectSubtitle: string; + projectDescription: string; + stats: Array<{ + label: string; + value: string; + }>; + videoUrl: string; + linkUrl: string; +} + +const { role, client, year, region, projectTitle, projectSubtitle, projectDescription, stats, videoUrl, linkUrl } = Astro.props; ---
- +
@@ -13,7 +30,7 @@ playsinline class="w-full h-full object-cover opacity-70 transition-opacity duration-700 group-hover:opacity-100" > - +
@@ -30,19 +47,19 @@
/// Role - VFX Sup + {role}
/// Client - Stink + {client}
/// Year - 2024 + {year}
/// Region - Global + {region}
@@ -51,7 +68,7 @@
@@ -63,33 +80,22 @@

- G-Star Olympics + {projectTitle} {projectSubtitle}

- Full CG environment production for the 2024 Olympic Campaign. - Orchestrated procedural city generation and AI-enhanced lighting workflows. + {projectDescription}

-
- Shot Count - 12 Sequences -
-
- Resolution - 4K DCI -
-
- Pipeline - Houdini / Solaris -
-
- Render - Karma XPU -
+ {stats.map((stat) => ( +
+ {stat.label} + {stat.value} +
+ ))}
diff --git a/src/components/sections/Hero.astro b/src/components/sections/Hero.astro index 158c0ef..90b5749 100644 --- a/src/components/sections/Hero.astro +++ b/src/components/sections/Hero.astro @@ -1,4 +1,14 @@ --- +interface Props { + headlineLine1: string; + headlineLine2: string; + portfolioYear: string; + location: string; + locationLabel: string; + bio: string; +} + +const { headlineLine1, headlineLine2, portfolioYear, location, locationLabel, bio } = Astro.props; ---
@@ -29,11 +39,11 @@
- Portfolio 2026 + {portfolioYear}
- Location - Colorado Springs, CO
+ {locationLabel} + {location}
00:00:00 MST
@@ -41,12 +51,12 @@

- VISUAL - ALCHEMIST + {headlineLine1} + {headlineLine2}

- I am a problem solver who loves visual effects. Creating end-to-end visual content for clients like Post Malone, Stinkfilms, and Adidas. Bridging creative vision with technical execution. + {bio}

diff --git a/src/components/sections/Skills.astro b/src/components/sections/Skills.astro index 38e7030..7483eb6 100644 --- a/src/components/sections/Skills.astro +++ b/src/components/sections/Skills.astro @@ -1,5 +1,27 @@ --- import { Image } from 'astro:assets'; + +interface Props { + sectionTitle: string; + sectionSubtitle: string; + description: string; + skills: Array<{ + id: string; + domain: string; + tools: string; + proficiency: string; + }>; +} + +const { sectionTitle, sectionSubtitle, description, skills } = Astro.props; + +// Image map for skill data attributes +const imageMap: Record = { + "01": "compositing", + "02": "3d", + "03": "ai", + "04": "dev" +}; ---
@@ -10,16 +32,16 @@ import { Image } from 'astro:assets';

- Technical + {sectionTitle} - Arsenal + {sectionSubtitle}

- A comprehensive suite of tools and workflows designed for high-fidelity visual production and pipeline automation. + {description}

@@ -35,75 +57,32 @@ import { Image } from 'astro:assets'; - -
-
- 01 - 01 -
-
-

Compositing

- -
-
-
- Nuke/NukeX • ComfyUI • After Effects • Photoshop -
- -
- - -
-
- 02 - 02 -
-
-

3D Generalist

-
-
- Houdini • Blender • Maya • USD • Solaris -
- -
- - -
-
- 03 - 03 -
-
-

AI Integration

-
-
- Stable Diffusion • LoRA • Datasets • Python -
- -
- - -
-
- 04 - 04 -
-
-

Development

-
-
- Python • React • Docker • Linux • Pipeline -
- -
+ {skills.map((skill, index) => { + const proficiencyClass = skill.proficiency === "Expert" || skill.proficiency === "Specialist" + ? "border-brand-accent/50 text-brand-accent bg-brand-accent/5" + : "border-white/20 text-slate-300"; + + return ( +
+
+ {skill.id} + {skill.id} +
+
+

{skill.domain}

+ {index === 0 && ( +
+ )} +
+
+ {skill.tools} +
+ +
+ ); + })} diff --git a/src/content.config.ts b/src/content.config.ts index ce37c7f..2ec7509 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -16,4 +16,90 @@ const blog = defineCollection({ }), }); -export const collections = { blog }; +const sections = defineCollection({ + loader: glob({ base: './src/content/sections', pattern: '**/*.{md,mdx}' }), + schema: z.object({ + // Hero section + headlineLine1: z.string().optional(), + headlineLine2: z.string().optional(), + portfolioYear: z.string().optional(), + location: z.string().optional(), + locationLabel: z.string().optional(), + bio: z.string().optional(), + // Experience section + sectionTitle: z.string().optional(), + sectionSubtitle: z.string().optional(), + sectionLabel: z.string().optional(), + description: z.string().optional(), + // Experience entries + entries: z.array(z.object({ + systemId: z.string(), + status: z.string(), + dates: z.string(), + company: z.string(), + role: z.string(), + tags: z.array(z.string()).optional(), + description: z.string(), + achievements: z.array(z.object({ + label: z.string(), + text: z.string(), + })).optional(), + link: z.object({ + url: z.string(), + text: z.string(), + }).optional(), + })).optional(), + // Skills entries + skills: z.array(z.object({ + id: z.string(), + domain: z.string(), + tools: z.string(), + proficiency: z.string(), + })).optional(), + // Featured project + role: z.string().optional(), + client: z.string().optional(), + year: z.string().optional(), + region: z.string().optional(), + projectTitle: z.string().optional(), + projectSubtitle: z.string().optional(), + projectDescription: z.string().optional(), + stats: z.array(z.object({ + label: z.string(), + value: z.string(), + })).optional(), + videoUrl: z.string().optional(), + linkUrl: z.string().optional(), + }), +}); + +const pages = defineCollection({ + loader: glob({ base: './src/content/pages', pattern: '**/*.{md,mdx}' }), + schema: z.object({ + pageTitleLine1: z.string().optional(), + pageTitleLine2: z.string().optional(), + availabilityText: z.string().optional(), + email: z.string().optional(), + location: z.string().optional(), + locationCountry: z.string().optional(), + coordinates: z.string().optional(), + socialLinks: z.array(z.object({ + name: z.string(), + url: z.string(), + })).optional(), + formLabels: z.object({ + name: z.string().optional(), + email: z.string().optional(), + subject: z.string().optional(), + message: z.string().optional(), + submit: z.string().optional(), + transmissionUplink: z.string().optional(), + }).optional(), + subjectOptions: z.array(z.object({ + value: z.string(), + label: z.string(), + })).optional(), + }), +}); + +export const collections = { blog, sections, pages }; diff --git a/src/content/pages/contact.mdx b/src/content/pages/contact.mdx new file mode 100644 index 0000000..e5629a5 --- /dev/null +++ b/src/content/pages/contact.mdx @@ -0,0 +1,33 @@ +--- +pageTitleLine1: "Project" +pageTitleLine2: "Inquiry" +availabilityText: "Available for freelance commissions and studio collaborations. Currently booking Q3 2026." +email: "nicholai@nicholai.work" +location: "Colorado Springs, CO" +locationCountry: "United States" +coordinates: "38.8339° N, 104.8214° W" +socialLinks: + - name: "Instagram" + url: "#" + - name: "LinkedIn" + url: "#" + - name: "Vimeo" + url: "#" +formLabels: + transmissionUplink: "Transmission Uplink" + name: "/// Identification Name" + email: "/// Return Address" + subject: "/// Subject Protocol" + message: "/// Message Data" + submit: "Transmit Message" +subjectOptions: + - value: "project" + label: "New Project Commission" + - value: "collab" + label: "Studio Collaboration" + - value: "press" + label: "Press / Media" + - value: "other" + label: "Other Inquiry" +--- + diff --git a/src/content/sections/experience.mdx b/src/content/sections/experience.mdx new file mode 100644 index 0000000..743a92b --- /dev/null +++ b/src/content/sections/experience.mdx @@ -0,0 +1,43 @@ +--- +sectionTitle: "Experience" +sectionSubtitle: "History" +sectionLabel: "/// Career Timeline" +description: "Bridging creative vision with technical execution. From running a dedicated VFX studio to high-end freelance supervision." +entries: + - systemId: "SYS.01" + status: "ACTIVE" + dates: "2022 — PRESENT" + company: "Biohazard VFX" + role: "Founder & Owner" + tags: + - "Studio Lead" + - "Pipeline Arch" + description: "Founded and 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." + achievements: + - label: "Key Achievement" + text: "Designed 7-plate reconciliation workflows for ENHYPEN (projection mapping live action onto CAD)." + - label: "System Impact" + text: "Developed QA systems for AI-generated assets, transforming mid-tier output into production-ready deliverables." + link: + url: "https://biohazardvfx.com" + text: "Visit Studio Uplink" + - systemId: "SYS.02" + status: "ARCHIVED" + dates: "SUMMER 2024" + company: "Stinkfilms" + role: "VFX Supervisor" + description: "Led Biohazard VFX team (60+ artists) alongside director Felix Brady to create a brand film for G-Star Raw. Managed full CG environments in Blender/Houdini." + link: + url: "/blog/gstar-raw-olympics/" + text: "Access Case Data" + - systemId: "SYS.03" + status: "DAEMON" + dates: "2016 — PRESENT" + company: "Freelance" + role: "Senior Compositor" + description: "Taking on select freelance compositing and 3D work alongside studio operations. Clients include Abyss Digital, Atlantic, Interscope." + tags: + - "Nuke" + - "Flame" +--- + diff --git a/src/content/sections/featured-project.mdx b/src/content/sections/featured-project.mdx new file mode 100644 index 0000000..82ee864 --- /dev/null +++ b/src/content/sections/featured-project.mdx @@ -0,0 +1,21 @@ +--- +role: "VFX Sup" +client: "Stink" +year: "2024" +region: "Global" +projectTitle: "G-Star" +projectSubtitle: "Olympics" +projectDescription: "Full CG environment production for the 2024 Olympic Campaign. Orchestrated procedural city generation and AI-enhanced lighting workflows." +stats: + - label: "Shot Count" + value: "12 Sequences" + - label: "Resolution" + value: "4K DCI" + - label: "Pipeline" + value: "Houdini / Solaris" + - label: "Render" + value: "Karma XPU" +videoUrl: "https://media.nicholai.work/FF_PUFF_GStar_DC_v08_4608x3164.mp4" +linkUrl: "/blog/gstar-raw-olympics/" +--- + diff --git a/src/content/sections/hero.mdx b/src/content/sections/hero.mdx new file mode 100644 index 0000000..8c5887d --- /dev/null +++ b/src/content/sections/hero.mdx @@ -0,0 +1,9 @@ +--- +headlineLine1: "VISUAL" +headlineLine2: "ALCHEMIST" +portfolioYear: "Portfolio 2026" +location: "Colorado Springs, CO" +locationLabel: "Location" +bio: "I am a problem solver who loves visual effects. Creating end-to-end visual content for clients like Post Malone, Stinkfilms, and Adidas. Bridging creative vision with technical execution." +--- + diff --git a/src/content/sections/skills.mdx b/src/content/sections/skills.mdx new file mode 100644 index 0000000..6b44c96 --- /dev/null +++ b/src/content/sections/skills.mdx @@ -0,0 +1,23 @@ +--- +sectionTitle: "Technical" +sectionSubtitle: "Arsenal" +description: "A comprehensive suite of tools and workflows designed for high-fidelity visual production and pipeline automation." +skills: + - id: "01" + domain: "Compositing" + tools: "Nuke/NukeX • ComfyUI • After Effects • Photoshop" + proficiency: "Expert" + - id: "02" + domain: "3D Generalist" + tools: "Houdini • Blender • Maya • USD • Solaris" + proficiency: "Advanced" + - id: "03" + domain: "AI Integration" + tools: "Stable Diffusion • LoRA • Datasets • Python" + proficiency: "Specialist" + - id: "04" + domain: "Development" + tools: "Python • React • Docker • Linux • Pipeline" + proficiency: "Full Stack" +--- + diff --git a/src/pages/contact.astro b/src/pages/contact.astro index 4800cc4..8fd6a46 100644 --- a/src/pages/contact.astro +++ b/src/pages/contact.astro @@ -1,8 +1,13 @@ --- import BaseLayout from '../layouts/BaseLayout.astro'; import { SITE_TITLE } from '../consts'; +import { getEntry } from 'astro:content'; const pageTitle = `Contact | ${SITE_TITLE}`; + +// Fetch contact page content +const contactEntry = await getEntry('pages', 'contact'); +const contactContent = contactEntry.data; --- @@ -22,14 +27,13 @@ const pageTitle = `Contact | ${SITE_TITLE}`;

- Project - Inquiry + {contactContent.pageTitleLine1} + {contactContent.pageTitleLine2}

- Available for freelance commissions and studio collaborations. - Currently booking Q3 2026. + {contactContent.availabilityText}

@@ -40,7 +44,7 @@ const pageTitle = `Contact | ${SITE_TITLE}`;
- Transmission Uplink + {contactContent.formLabels?.transmissionUplink}
@@ -54,7 +58,7 @@ const pageTitle = `Contact | ${SITE_TITLE}`; required />
@@ -68,7 +72,7 @@ const pageTitle = `Contact | ${SITE_TITLE}`; required /> @@ -84,28 +88,18 @@ const pageTitle = `Contact | ${SITE_TITLE}`; @@ -120,13 +114,13 @@ const pageTitle = `Contact | ${SITE_TITLE}`; required >
@@ -139,8 +133,8 @@ const pageTitle = `Contact | ${SITE_TITLE}`; @@ -148,11 +142,11 @@ const pageTitle = `Contact | ${SITE_TITLE}`;

Coordinates

- Colorado Springs, CO
- United States + {contactContent.location}
+ {contactContent.locationCountry}

- 38.8339° N, 104.8214° W + {contactContent.coordinates}
@@ -160,24 +154,14 @@ const pageTitle = `Contact | ${SITE_TITLE}`;

Social Feed

@@ -680,7 +664,7 @@ const pageTitle = `Contact | ${SITE_TITLE}`; showResponse(); // Reset button state - submitText.textContent = 'Transmit Message'; + submitText.textContent = submitText.getAttribute('data-default-text') || 'Transmit Message'; submitBtn.disabled = false; } catch (markdownError) { @@ -713,8 +697,9 @@ const pageTitle = `Contact | ${SITE_TITLE}`; // Update button to failure state submitText.textContent = 'Transmission Failed'; + const defaultText = submitText.getAttribute('data-default-text') || 'Transmit Message'; setTimeout(() => { - submitText.textContent = 'Transmit Message'; + submitText.textContent = defaultText; submitBtn.disabled = false; }, 2000); diff --git a/src/pages/index.astro b/src/pages/index.astro index 7100cf1..bdc3377 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -4,23 +4,68 @@ import Hero from '../components/sections/Hero.astro'; import Experience from '../components/sections/Experience.astro'; import FeaturedProject from '../components/sections/FeaturedProject.astro'; import Skills from '../components/sections/Skills.astro'; +import { getEntry } from 'astro:content'; + +// Fetch all section content +const heroEntry = await getEntry('sections', 'hero'); +const experienceEntry = await getEntry('sections', 'experience'); +const skillsEntry = await getEntry('sections', 'skills'); +const featuredProjectEntry = await getEntry('sections', 'featured-project'); + +// Extract content from entries +const heroContent = { + headlineLine1: heroEntry.data.headlineLine1 || '', + headlineLine2: heroEntry.data.headlineLine2 || '', + portfolioYear: heroEntry.data.portfolioYear || '', + location: heroEntry.data.location || '', + locationLabel: heroEntry.data.locationLabel || '', + bio: heroEntry.data.bio || '', +}; + +const experienceContent = { + sectionTitle: experienceEntry.data.sectionTitle || '', + sectionSubtitle: experienceEntry.data.sectionSubtitle || '', + sectionLabel: experienceEntry.data.sectionLabel || '', + description: experienceEntry.data.description || '', + entries: experienceEntry.data.entries || [], +}; + +const skillsContent = { + sectionTitle: skillsEntry.data.sectionTitle || '', + sectionSubtitle: skillsEntry.data.sectionSubtitle || '', + description: skillsEntry.data.description || '', + skills: skillsEntry.data.skills || [], +}; + +const featuredProjectContent = { + role: featuredProjectEntry.data.role || '', + client: featuredProjectEntry.data.client || '', + year: featuredProjectEntry.data.year || '', + region: featuredProjectEntry.data.region || '', + projectTitle: featuredProjectEntry.data.projectTitle || '', + projectSubtitle: featuredProjectEntry.data.projectSubtitle || '', + projectDescription: featuredProjectEntry.data.projectDescription || '', + stats: featuredProjectEntry.data.stats || [], + videoUrl: featuredProjectEntry.data.videoUrl || '', + linkUrl: featuredProjectEntry.data.linkUrl || '', +}; --- - +
- +
- - + +