Files
mintel.me/apps/web/src/components/home/PortraitSection.tsx
T
mmintelandClaude Opus 5.5 3e0c9a1605 feat: a red thread through the homepage, in words and as a line
The rail and the "next, you are wondering" links are gone (owner: flat, and
the question stood twice in a row). The page now reads from top to bottom:

Every chapter opens with one sentence, and the sentences follow each other
as the way of a project: you need someone who builds it, first we find out
what you need, sometimes it is less work by hand, sometimes a meeting, then
it always runs the same way, in the end something runs, a few questions
remain, and it starts with an email.

One line runs down the whole page and draws itself as the visitor scrolls.
Under each sentence it crosses the page, stands a figure on the line
(diamond, hexagon, screen, circle, square, triangle) and continues down the
other side; a glowing dot travels at its head and comes to rest in front of
the last sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 10:35:55 +02:00

88 lines
3.4 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;
portraitAlt: string;
/** The sentence of the story this chapter opens with. */
story: string;
children: React.ReactNode;
}> = ({ id, index, label, title, portraitAlt, story, children }) => (
<section
id={id}
data-thread-start=""
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={portraitAlt}
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] }}
>
<p className="m-0 mb-10 max-w-2xl font-sans text-2xl font-bold leading-[1.1] tracking-tight text-white md:mb-16 md:text-5xl">
{story}
</p>
<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>
);