Skip to content
6

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 'motion/react';

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';

const 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>
  );
};

export default Portfolio;

Dependencies

shadcn registry

button

npm

gsapmotion