/* Sections part 1: Nav, Hero, Marquee, About */ const { useState: uS1, useEffect: uE1, useRef: uR1 } = React; /* ---------------- NAV ---------------- */ function Nav() { const [scrolled, setScrolled] = uS1(false); uE1(() => { const onScroll = () => setScrolled(window.scrollY > 24); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); const S = window.SITE; const go = (e, id) => { e.preventDefault(); document.getElementById(id)?.scrollIntoView({ behavior: "smooth" }); }; return ( ); } /* ---------------- HERO ---------------- */ function CodeWindow() { // typewriter for the code body — a small React component "intro" const lines = [ [{ t: "com", v: "// Frontend engineer, full-stack range" }], [{ t: "key", v: "const " }, { t: "fn", v: "engineer" }, { t: "punc", v: " = {" }], [{ t: "prop", v: " name" }, { t: "punc", v: ": " }, { t: "str", v: "'Fhillip G. Castillo'" }, { t: "punc", v: "," }], [{ t: "prop", v: " stack" }, { t: "punc", v: ": [" }, { t: "str", v: "'React'" }, { t: "punc", v: ", " }, { t: "str", v: "'Next.js'" }, { t: "punc", v: ", " }, { t: "str", v: "'TypeScript'" }, { t: "punc", v: "]," }], [{ t: "prop", v: " focus" }, { t: "punc", v: ": " }, { t: "str", v: "'scalable, user-centric UIs'" }, { t: "punc", v: "," }], [{ t: "prop", v: " shipsTo" }, { t: "punc", v: ": " }, { t: "str", v: "'production'" }, { t: "punc", v: "," }], [{ t: "prop", v: " available" }, { t: "punc", v: ": " }, { t: "key", v: "true" }, { t: "punc", v: "," }], [{ t: "punc", v: "};" }], ]; const [count, setCount] = uS1(0); // chars revealed const total = lines.reduce((a, l) => a + l.reduce((b, s) => b + s.v.length, 0) + 1, 0); const hostRef = uR1(null); uE1(() => { let id = 0; const startTimer = setTimeout(() => { let c = 0; id = setInterval(() => { c += 1; setCount(c); if (c >= total) clearInterval(id); }, 24); }, 650); return () => { clearTimeout(startTimer); clearInterval(id); }; }, [total]); // build rendered lines based on count let remaining = count; const done = count >= total; return (
engineer.ts
{lines.map((line, li) => { const out = []; for (const seg of line) { if (remaining <= 0) break; const take = Math.min(seg.v.length, remaining); out.push({ t: seg.t, v: seg.v.slice(0, take) }); remaining -= take; } remaining -= 1; // newline cost const lineHasContent = out.length > 0; if (!lineHasContent && remaining < 0 && li > 0) return null; return (
{out.map((s, si) => {s.v})} {!done && remaining <= 0 && lineHasContent && }
); })} {done &&
}
); } function Hero() { const S = window.SITE; const role = useTypewriter(S.roles, { typeSpeed: 75, deleteSpeed: 38, hold: 1700 }); const go = (e, id) => { e.preventDefault(); document.getElementById(id)?.scrollIntoView({ behavior: "smooth" }); }; return (
{S.availability}

Hi, I'm Fhillip.
I build the web.

I work as a {role}

{S.tagline}

go(e, "contact")}>Hire me go(e, "experience")}>View experience
{S.location} React · Next.js · TypeScript
Next.js 15 TypeScript Design Systems
); } /* ---------------- MARQUEE ---------------- */ function Marquee() { const items = window.SITE.marquee; const row = [...items, ...items]; return ( ); } /* ---------------- ABOUT ---------------- */ function Stat({ value, suffix, label }) { const [ref, val] = useCountUp(value); return (
{val}{suffix}
{label}
); } function About() { const S = window.SITE; return (
{S.avatar ? {S.name} : {S.monogram}}
{S.monogram}
{S.name}
Full-Stack · Frontend-focused
About me

Frontend craft,
full-stack range.

{S.about.map((p, i) => (

{p}

))}
{S.stats.map((s, i) => )}
); } Object.assign(window, { Nav, Hero, Marquee, About });