Files
mintel.me/apps/web/src/components/home/PortraitSection.tsx
T
mmintelandClaude Opus 5.5 e89a248ca5 feat: binary glow effects, refined drawings and calls to action
Dark surfaces now carry light: frames glow along their edge and shed binary
digits (BitAura), dark sections open with a lit seam (BitSeam), the career
path is a line of light and "My work" became a dark stage. Buttons carry a
travelling light and a spot that follows the pointer (BitGlow).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:07:09 +02:00

81 lines
3.1 KiB
TypeScript

"use client";
import { BitSeam } from "@/src/components/bits/BitSeam";
import * as React from "react";
import Image from "next/image";
import { motion } from "framer-motion";
import { BitReveal } from "@/src/components/bits/BitReveal";
import { BitWipe } from "@/src/components/bits/BitWipe";
import { DecodeText } from "@/src/components/bits/DecodeText";
/**
* PortraitSection: the introduction, with the portrait fading out of a dark surface
* and the text set over it.
*/
export const PortraitSection: React.FC<{
id?: string;
index: string;
label: string;
title: React.ReactNode;
children: React.ReactNode;
}> = ({ id, index, label, title, children }) => (
<section
id={id}
className="relative scroll-mt-24 overflow-hidden bg-slate-900 text-white"
>
{/* Portrait: right side on wide screens, top on small ones. */}
<motion.div
className="relative h-[110vw] w-full md:absolute md:inset-y-0 md:right-0 md:h-auto md:w-[62%]"
initial={{ scale: 1.06 }}
whileInView={{ scale: 1 }}
viewport={{ once: true, margin: "-10%" }}
transition={{ duration: 1.4, ease: [0.16, 1, 0.3, 1] }}
>
<Image
src="/marc-mintel.png"
alt="Marc Mintel, freelance web developer"
fill
sizes="(min-width: 768px) 62vw, 100vw"
className="object-cover object-[50%_18%] grayscale"
priority={false}
/>
{/* Slow light behind the fades, so the dark surface is not flat. */}
<div className="bit-aurora" aria-hidden="true" />
{/* Fades: into the surface on the left, and at top and bottom. */}
<div className="absolute inset-0 hidden bg-gradient-to-r from-slate-900 via-slate-900/75 to-slate-900/10 md:block" />
<div className="absolute inset-x-0 bottom-0 h-2/5 bg-gradient-to-t from-slate-900 to-transparent" />
<div className="absolute inset-x-0 top-0 h-24 bg-gradient-to-b from-slate-900 to-transparent" />
{/* The portrait assembles itself out of binary digits. */}
<BitReveal />
</motion.div>
<div className="relative z-10 mx-auto w-full max-w-[1400px] px-5 pb-20 md:px-12 md:py-40">
<motion.div
className="-mt-24 max-w-3xl md:mt-0"
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-10%" }}
transition={{ duration: 0.8, delay: 0.2, ease: [0.16, 1, 0.3, 1] }}
>
<div className="mb-8 flex items-center gap-4 md:mb-12">
<span className="font-mono text-[11px] font-bold tracking-[0.2em] text-white">
{index}
</span>
<span className="h-px w-10 bg-slate-600" />
<DecodeText
text={label}
className="font-mono text-[11px] uppercase tracking-[0.25em] text-slate-400"
/>
</div>
<BitWipe tone="light" delay={0.35}>
<h2 className="m-0 text-5xl font-bold leading-[0.95] tracking-tighter text-white md:text-7xl lg:text-[6.5rem]">
{title}
</h2>
</BitWipe>
<div className="mt-10 md:mt-14">{children}</div>
</motion.div>
</div>
<BitSeam density={1} />
</section>
);