Portfolio

Dark, single-page personal portfolio: a counter loading screen, an HLS video hero with a floating nav and a cycling role line, a bento work grid, a journal list, a scroll-pinned parallax gallery with lightbox, count-up stats and a video contact footer. Self-contained dark palette, driven by GSAP and Framer Motion.

Preview

Installation

npx shadcn@latest add https://hirael.com/r/portfolio.json

Code

components/templates/portfolio/portfolio.tsx
"use client";

import * as React from "react";
import { MotionConfig } from "framer-motion";

import { cn } from "@/lib/utils";

import { Contact } from "./contact";
import { Explorations } from "./explorations";
import { inter, instrumentSerif } from "./fonts";
import { Hero } from "./hero";
import { Journal } from "./journal";
import { LoadingScreen } from "./loading-screen";
import { SelectedWorks } from "./selected-works";
import { Stats } from "./stats";
import { PORTFOLIO_STYLES } from "./styles";

export default function Portfolio() {
  const [isLoading, setIsLoading] = React.useState(true);

  return (
    <div
      data-slot="portfolio"
      className={cn(
        inter.variable,
        instrumentSerif.variable,
        "min-h-svh bg-[hsl(var(--bg))] text-[hsl(var(--text))] antialiased",
      )}
    >
      <style dangerouslySetInnerHTML={{ __html: PORTFOLIO_STYLES }} />

      <MotionConfig reducedMotion="user">
        {isLoading ? (
          <LoadingScreen onComplete={() => setIsLoading(false)} />
        ) : null}

        <Hero start={!isLoading} />
        <SelectedWorks />
        <Journal />
        <Explorations />
        <Stats />
        <Contact />
      </MotionConfig>
    </div>
  );
}

Dependencies

npm

gsapframer-motionhls.js