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>
88 lines
3.4 KiB
TypeScript
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>
|
|
);
|