Communitygithub.com

ZeroSum-Solutions/mishmash

A monochrome, editorial landing page for a fictional Natural History Museum paleontology collection, featuring a three-section continuous scroll: a full-viewport hero with a delayed background video reveal and an animated geometric "NHM" SVG logotype (per-polygon slide-up reveal), an "Explore Our World" section with scroll-revealed display heading and action pills, and a dark "Ancient Collection" chapter browser with auto-cycling fossil images and a custom SVG `feTurbulence`/`feDisplacementMap` sand-dissolve transition effect. Built with React 19, Vite 6, Tailwind CSS 4 (CSS-first config), and Motion (Framer Motion), in a strictly monochrome black/white/gray palette — no color accents.

mishmash 是什么?

mishmash is a Claude Code agent skill that a monochrome, editorial landing page for a fictional Natural History Museum paleontology collection, featuring a three-section continuous scroll: a full-viewport hero with a delayed background video reveal and an animated geometric "NHM" SVG logotype (per-polygon slide-up reveal), an "Explore Our World" section with scroll-revealed display heading and action pills, and a dark "Ancient Collection" chapter browser with auto-cycling fossil images and a custom SVG `feTurbulence`/`feDisplacementMap` sand-dissolve transition effect. Built with React 19, Vite 6, Tailwind CSS 4 (CSS-first config), and Motion (Framer Motion), in a strictly monochrome black/white/gray palette — no color accents.

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ZeroSum-Solutions/mishmash/tree/HEAD/design-templates/nhm-paleontology-landing

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

NHM Paleontology — Natural History Museum Monochrome Landing Page

Landing page vendored from the MIT-licensed pulkitxm/claude-directory gallery.

A monochrome, editorial landing page for a fictional Natural History Museum paleontology collection, featuring a three-section continuous scroll: a full-viewport hero with a delayed background video reveal and an animated geometric "NHM" SVG logotype (per-polygon slide-up reveal), an "Explore Our World" section with scroll-revealed display heading and action pills, and a dark "Ancient Collection" chapter browser with auto-cycling fossil images and a custom SVG feTurbulence/feDisplacementMap sand-dissolve transition effect. Built with React 19, Vite 6, Tailwind CSS 4 (CSS-first config), and Motion (Framer Motion), in a strictly monochrome black/white/gray palette — no color accents.

Workflow

  1. Clone example.html into the user's workspace as the working file.
  2. Replace placeholder content with the user's real brand name, headlines, body copy, numbers, and imagery. Match existing image dimensions when swapping assets.
  3. Preserve the design system. The palette, type scale, spacing rhythm, and motion in the build spec below are the identity — do not substitute fonts, recolour the palette, or strip decorative elements.
  4. Extend by duplicating sections, never by importing a layout from another template. If a section is missing, design it from scratch in this template's own vocabulary.
  5. Keep motion accessible. Every animation must stay behind prefers-reduced-motion, as the build spec requires.

Output contract

Emit between <artifact> tags:

<artifact identifier="nhm-paleontology-landing" type="text/html" title="NHM Paleontology — Natural History Museum Monochrome Landing Page">
<!doctype html>
<html>...</html>
</artifact>

Build spec

The upstream prompt that produced this design, verbatim.

NHM — Natural History Museum Paleontology Landing

Overview

Build a single-page, monochrome landing page for the Natural History Museum's paleontology collection. The page is one continuous scroll with three sections — a full-viewport hero with a delayed background video and a geometric "NHM" logotype, an "Explore Our World" intro section, and a dark "Ancient Collection" chapter browser featuring an SVG-filter sand/dissolve image transition. The entire page is a single App.tsx component plus a SandTransitionImage helper and a LeafIcon helper in the same file.

Tech Stack

  • Framework: React 19 (react, react-dom ^19.0.1) with StrictMode
  • Build tool: Vite 6 (vite ^6.2.3, @vitejs/plugin-react ^5.0.4)
  • Language: TypeScript (typescript ~5.8.2, @types/react ^19.0.10, @types/react-dom ^19.0.4)
  • Styling: Tailwind CSS 4 (tailwindcss ^4.1.14, @tailwindcss/vite ^4.1.14) — CSS-first config via @theme
  • Animation: Motion / Framer Motion (motion ^12.23.24), imported from motion/react
  • Icons: Lucide (lucide-react ^0.546.0)
  • Fonts (Google Fonts): Inter (sans, weights 300/400/500/600) and JetBrains Mono (mono, weights 400/500)
  • Notable techniques: delayed background video reveal, auto-cycling chapter carousel, SVG feTurbulence / feDisplacementMap sand-dissolve filter driven by requestAnimationFrame, geometric polygon logotype animated per-polygon, whileInView scroll reveals.

Global Setup

index.html

  • lang="en", <meta charset="UTF-8" />, viewport meta width=device-width, initial-scale=1.0.
  • Description meta: NHM — Natural History Museum. Exploring the story of life on earth through science, discovery and wonder.
  • Title: NHM — Natural History Museum
  • Root: <div id="root"></div> and <script type="module" src="/src/main.tsx"></script>.

src/main.tsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

src/index.css

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
@import "tailwindcss";

@theme {
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
}

@layer base {
  body {
    background-color: #fcfcfc;
    color: #111;
    overflow-x: hidden;
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
  }

  ::selection {
    background-color: #000;
    color: #fff;
  }
}

@layer utilities {
  .text-mega {
    font-size: 21vw;
    line-height: 0.75;
    letter-spacing: -0.04em;
  }
}

Global styling summary: background #fcfcfc, text #111, selection #000 background / #fff text, overflow-x: hidden, default font font-sans (Inter), antialiased. The .text-mega utility (font-size: 21vw, line-height: 0.75, letter-spacing: -0.04em) is defined though not required by every layout.

Data, State & Constants

Imports

import { useEffect, useRef, useState } from "react";
import { AnimatePresence, motion, usePresence } from "motion/react";
import type { Variants } from "motion/react";
import {
  ArrowRight,
  ArrowUpRight,
  Bone,
  BookOpen,
  Dna,
  Gem,
  Leaf,
  Plus,
} from "lucide-react";

Asset URLs (local, vendored under /assets/)

Note: assets are served locally from /assets/..., not from a remote CDN. The original brief referenced Cloudinary URLs; the project vendors them locally with these exact (lowercase, case-sensitive) filenames.

const VIDEO_URL =
  "/assets/magnific_use-img-2-as-the-exact-ba_Piu3X0W42C_wnrc8f.mp4";

const PTERODACTYL_URL =
  "/assets/ChatGPT_Image_May_23_2026_12_24_44_PM_1_lv1dne.png";

Chapters data

const chaptersData = [
  { name: "Age of Dinosaurs",         image: "/assets/01_udnber.png" },
  { name: "Fossils of Ancient Life",  image: "/assets/02_pmvxxl.png" },
  { name: "Reptiles of the Mesozoic", image: "/assets/03_hcp3jc.png" },
  { name: "Marine Fossil Gallery",    image: "/assets/04_get63z.png" },
  { name: "Prehistoric Giants",       image: "/assets/05_kz1tyu.png" },
];

Other constants

const NAV_LINKS = ["Visit", "Exhibitions", "Discover", "Learn", "About"];

const ACTION_PILLS = [
  { icon: Bone, label: "Dinosaurs" },
  { icon: Dna, label: "Ancient Life" },
  { icon: Gem, label: "Minerals" },
  { icon: Leaf, label: "Fossils" },
  { icon: BookOpen, label: "Learn More" },
];

const EASE: [number, number, number, number] = [0.16, 1, 0.3, 1];

Component state (inside App)

const [showVideo, setShowVideo] = useState(false);
const [activeChapter, setActiveChapter] = useState(2); // starts at "Reptiles of the Mesozoic"
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  • showVideo flips to true after a 2800ms setTimeout (cleared on unmount).
  • activeChapter auto-cycles every 3500ms via setInterval, wrapping (prev + 1) % 5 (cleared on unmount).

Animation Variants

const fadeUp: Variants = {
  initial: { opacity: 0, y: 20 },
  animate: { opacity: 1, y: 0 },
};

const fadeUpTransition = { duration: 0.8, ease: "easeOut" as const };

const letterBlock: Variants = {
  initial: { y: 120, opacity: 0 },
  animate: {
    y: 0,
    opacity: 1,
    transition: { duration: 1.2, ease: EASE },
  },
};

const logoVariants: Variants = {
  initial: { scale: 1.03 },
  animate: {
    scale: 1,
    transition: {
      duration: 1.2,
      ease: EASE,
      staggerChildren: 0.06,
      delayChildren: 0.1,
    },
  },
};

const staggerHeader: Variants = {
  animate: { transition: { staggerChildren: 0.1, delayChildren: 0.1 } },
};

const staggerLeft: Variants = {
  animate: { transition: { staggerChildren: 0.15, delayChildren: 0.6 } },
};

const staggerRight: Variants = {
  animate: { transition: { staggerChildren: 0.15, delayChildren: 0.9 } },
};

const staggerPills: Variants = {
  animate: { transition: { staggerChildren: 0.1, delayChildren: 0.3 } },
};

Layout

Root element: <main className="w-full"> containing three <section> blocks.


Section 1 — Hero (full viewport height)

Container: relative flex min-h-screen w-full flex-col overflow-hidden

1D. Background video

Rendered first (sits behind everything), gated by showVideo inside AnimatePresence.

  • Wrapper motion.div: initial={{ opacity: 0 }}, animate={{ opacity: 1 }}, transition={{ duration: 1.4, ease: "easeOut" }}, class pointer-events-none absolute top-0 left-0 z-0 h-full w-full.
  • <video>: autoPlay loop muted playsInline, src={VIDEO_URL}, class h-full w-full object-cover.

1A. Header — NHM logotype

motion.header with initial="initial" animate="animate" variants={staggerHeader}, class relative z-20 px-6 pt-6 md:px-16.

  • motion.h1 uses variants={logoVariants}, class w-full. Contains an <span className="sr-only">NHM — Natural History Museum</span> plus the inline SVG.
  • SVG: viewBox="0 0 840 100", class w-full overflow-hidden fill-[#111], aria-hidden="true".
  • Letters are data-driven from LOGO_LETTERS; each letter is a <g transform={letter.translate}>, and each polygon is a motion.polygon with variants={letterBlock} (slides up from y: 120).
const LOGO_LETTERS: { translate: string; polygons: string[] }[] = [
  {
    // N
    translate: "translate(0,0)",
    polygons: [
      "0,0 14,0 14,100 0,100",
      "200,0 214,0 214,100 200,100",
      "0,0 33,0 214,100 181,100",
    ],
  },
  {
    // H
    translate: "translate(280,0)",
    polygons: [
      "0,0 14,0 14,100 0,100",
      "200,0 214,0 214,100 200,100",
      "14,43 200,43 200,57 14,57",
    ],
  },
  {
    // M
    translate: "translate(560,0)",
    polygons: [
      "0,0 14,0 14,100 0,100",
      "266,0 280,0 280,100 266,100",
      "0,0 26,0 153,100 127,100",
      "254,0 280,0 153,100 127,100",
    ],
  },
];

1B. Sub-nav bar

motion.div with variants={fadeUp} transition={fadeUpTransition}, class mt-8 flex items-start justify-between gap-3 font-mono text-[10px] tracking-[0.2em] uppercase md:text-[11px].

  • Left column (w-[15%]): three <p> lines — Natura / History / Museum.
  • Arrow separator (hidden w-[5%] justify-center md:flex): Lucide ArrowRight, size={14}, strokeWidth={1}, class text-gray-400.
  • Center column (flex-1 leading-relaxed font-mono text-gray-800 md:flex-none md:w-[30%]): the copy "Exploring the story of life on earth through science, discovery and wonder." split into 3 lines on desktop (hidden md:block) and 4 lines on mobile (md:hidden):
    • Desktop: Exploring the story of life / on earth through science, / discovery and wonder.
    • Mobile: Exploring the story / of life on earth / through science, / discovery and wonder.
  • Arrow separator (same as above, hidden w-[5%] justify-center md:flex).
  • Right column / nav (hidden w-[15%] md:block): <ul className="space-y-1 text-gray-800"> mapping NAV_LINKS — Visit, Exhibitions, Discover, Learn, About — each an <a href="#"> with class transition-colors hover:text-black hover:underline.
  • Hamburger button (far right, md:hidden): <button type="button"> with aria-label toggling between Open menu / Close menu, aria-expanded={isMobileMenuOpen}, onClick toggling isMobileMenuOpen, class group z-60 flex flex-col items-end gap-[6px] py-2 pl-4 md:hidden.
    • Two <span> bars, each base class h-[1.5px] bg-black transition-all duration-300.
    • When open: first bar w-8 translate-y-[3.75px] rotate-45; second bar w-8 -translate-y-[3.75px] -rotate-45 (forms an X).
    • When closed: first bar w-8 group-hover:w-6; second bar w-8 group-hover:w-10.

1C. Mobile menu overlay

AnimatePresence wrapping a motion.div shown when isMobileMenuOpen.

  • initial={{ y: -20, opacity: 0 }}, animate={{ y: 0, opacity: 1 }}, exit={{ y: -20, opacity: 0 }}, transition={{ duration: 0.4, ease: EASE }}.
  • Class: absolute top-full right-0 left-0 z-50 border-b border-gray-200 bg-[#fcfcfc] shadow-xl md:hidden.
  • <nav className="px-6 py-10"> with <ul className="space-y-6 font-mono text-sm tracking-[0.2em] uppercase"> mapping the same NAV_LINKS; each link's onClick closes the menu (setIsMobileMenuOpen(false)), class transition-colors hover:text-black hover:underline.

Hero body wrapper

<div className="relative z-10 flex w-full flex-1 items-start justify-between"> holds the left and right sidebars.

1E. Left sidebar content

motion.div with initial="initial" animate="animate" variants={staggerLeft}, class mt-20 w-[320px] px-10 sm:mt-28 md:mt-32 md:px-16.

  • Section indicator (motion.div variants={fadeUp}, class flex items-center gap-4 font-mono text-xs): <span>01</span> + <span className="h-[1.5px] w-16 bg-black/20" />.
  • Headline (motion.h2 variants={fadeUp}, class mt-6 text-[3.5rem] leading-[1] font-normal tracking-tight md:text-[5rem]): TIMELESS <br /> WONDERS.
  • Description (motion.p variants={fadeUp}, class mt-6 w-[240px] text-[13px] leading-[1.6] text-gray-700 md:text-[14px]): Step into the natural world and / discover the stories written / millions of years ago. (line breaks between each phrase).
  • CTA button (motion.div variants={fadeUp}, class mt-10): a <button type="button"> with class group relative overflow-hidden rounded-md border border-[#1a1a1a] bg-[#1a1a1a] px-6 py-3.5 shadow-sm transition-all duration-300 hover:-translate-y-[0.5px] hover:shadow-[3px_3px_0px_rgba(17,17,17,0.5)] active:translate-y-0 active:shadow-sm.
    • Sliding background panel (<span aria-hidden="true">): absolute inset-0 -translate-x-[101%] bg-[#fcfcfc] transition-transform duration-700 ease-[cubic-bezier(0.16,1,0.3,1)] group-hover:translate-x-0.
    • Inner content (<span className="relative flex items-center gap-3">):
      • LeafIcon with class h-5 w-5 text-white transition-all duration-500 group-hover:scale-110 group-hover:-rotate-12 group-hover:-translate-y-1 group-hover:text-[#111].
      • Label <span>Explore Now</span> with class text-[15px] font-medium text-white transition-colors duration-500 group-hover:text-[#111].

1F. Right sidebar (hidden on mobile)

motion.div with initial="initial" animate="animate" variants={staggerRight}, class mt-12 mr-10 hidden w-[200px] flex-col gap-10 md:mt-20 md:mr-16 md:flex.

  • Specimen info (motion.div variants={fadeUp}):
    • <h3 className="font-mono text-[10px] font-bold tracking-widest uppercase">Tyrannosaurus Rex</h3>
    • <p className="mt-2 text-[12px] leading-[1.6] text-gray-600"> — Late Cretaceous period / 68-66 million years ago (with <br />).
  • Stats (motion.div variants={fadeUp}, class flex gap-10): two stacks.
    • Label <p className="font-mono text-[10px] tracking-widest text-gray-500 uppercase">Length</p> + value <p className="mt-1 text-[13px] font-medium">12.3 m</p>.
    • Label Height + value 4.0 m (same classes).
  • View Details button (motion.button type="button" variants={fadeUp}, class group flex items-center gap-4):
    • Circle <span className="flex h-10 w-10 items-center justify-center rounded-full border border-gray-400 transition-colors duration-300 group-hover:border-black group-hover:bg-[#111]"> containing Lucide Plus, size={16}, strokeWidth={1.5}, class transition-colors duration-300 group-hover:text-white.
    • Label <span className="font-mono text-[10px] font-bold tracking-widest uppercase">View Details</span>.

1G. Bottom-left "Scroll to explore"

motion.div: initial={{ opacity: 0, y: 20 }}, animate={{ opacity: 1, y: 0 }}, transition={{ duration: 0.8, ease: "easeOut", delay: 1.2 }}, class absolute bottom-10 left-[2.5rem] z-10 hidden items-center gap-4 md:left-[4rem] md:flex.

  • Circle <span className="flex h-12 w-12 items-center justify-center gap-[4px] rounded-full border border-gray-300"> containing two thin vertical lines (<span className="h-[12px] w-[1px] bg-gray-600" /> × 2) forming a pause icon.
  • Label <span className="font-mono text-[10px] font-semibold tracking-widest text-gray-500 uppercase">Scroll to explore</span>.

Section 2 — Explore Our World

Container: relative z-20 flex min-h-[75vh] w-full flex-col items-center bg-[#fcfcfc] pt-24 pb-0 md:min-h-screen md:pt-32

2A. Section label

<p className="mb-12 font-mono text-[10px] tracking-[0.2em] md:text-[11px]">:

  • <span className="text-gray-500">[ 02 ]</span> then {" "} then <span className="font-bold text-gray-900 uppercase">Explore Our World</span>.

2B. Main heading

motion.h2: initial={{ y: 40, opacity: 0 }}, whileInView={{ y: 0, opacity: 1 }}, viewport={{ once: true, margin: "-100px" }}, transition={{ duration: 1, ease: EASE }}, class mb-12 max-w-[1000px] px-6 text-center text-[2.2rem] leading-[1.1] font-medium tracking-tight text-[#111] md:mb-16 md:text-[3.5rem] lg:text-[4.2rem].

Copy: Unearth the stories of our planet's past + <br className="hidden md:block" /> + through fossils, minerals, and ancient wonders. (the desktop-only break falls after "past").

2C. Action pills

motion.div: initial="initial", whileInView="animate", viewport={{ once: true }}, variants={staggerPills}, class mb-10 flex flex-wrap justify-center gap-3 px-6 md:mb-24 md:gap-4.

Maps ACTION_PILLS to motion.button type="button" items with variants={fadeUp} transition={fadeUpTransition}, class flex items-center gap-2 rounded-full border border-gray-300 bg-white/50 px-5 py-2.5 text-[11px] font-medium tracking-wider text-gray-800 uppercase backdrop-blur-sm transition-colors duration-300 hover:border-black hover:bg-black hover:text-white. Each contains the Lucide icon (size={14}, strokeWidth={2}) plus the label:

  1. Bone + Dinosaurs
  2. Dna + Ancient Life
  3. Gem + Minerals
  4. Leaf + Fossils
  5. BookOpen + Learn More

2D. Spacer

<div className="min-h-[220px] w-full md:min-h-[450px]" /> — provides room for the Section 3 pterodactyl image to overlap upward.

2E. Bottom text

<div className="pointer-events-none absolute bottom-0 left-0 flex w-full justify-between px-8 pb-8 md:px-16 md:pb-12"> with two <p> elements (both hidden font-mono text-[10px] font-medium tracking-widest text-gray-500 uppercase md:block):

  • Left: WE DON'T JUST TELL STORIES.
  • Right: PALEONTOLOGY (C) 2026

Section 3 — Ancient Collection (dark)

Container: relative z-30 flex w-full flex-col bg-[#0a0a0a] text-white

3A. Pterodactyl image (overlapping upward)

motion.img with src={PTERODACTYL_URL}, alt="Pterodactyl fossil skeleton in flight":

  • initial={{ y: "-65%", x: "-50%", opacity: 0 }}, whileInView={{ y: "-78%", x: "-50%", opacity: 1 }}, viewport={{ once: true, margin: "100px" }}, transition={{ duration: 1.4, ease: "easeOut" }}.
  • Class: pointer-events-none absolute top-0 left-1/2 z-0 w-[160vw] max-w-none md:w-[1100px].

3B. Heading area

<div className="z-10 mb-16 flex flex-col justify-between gap-12 px-8 pt-32 md:px-16 md:pt-48 xl:flex-row">.

Left — main heading <h2 className="max-w-[860px] text-[1.8rem] leading-[1.15] font-medium tracking-tight text-white md:text-[3rem] lg:text-[3.8rem] xl:text-[4rem]">:

  • Text Curated from millions of years of wonder then an inline icon group <span className="mx-2 inline-flex translate-y-[-4px] gap-2 align-middle md:mx-4 md:gap-3"> then & discovery.
  • The icon group maps [Bone, Dna, Leaf]; each is <span className="flex h-10 w-10 items-center justify-center rounded-full border border-gray-600 bg-black text-gray-400 transition-colors duration-300 hover:border-white hover:bg-white hover:text-black md:h-14 md:w-14"> containing the icon at size={22}, strokeWidth={1.5}.

Right — tagline + pills <div className="shrink-0 xl:text-right">:

  • Tagline <p className="mb-6 font-mono text-[9px] leading-relaxed tracking-widest text-gray-400 uppercase md:text-[10px]"> — WE DON'T JUST DISPLAY FOSSILS / WE SHARE EARTH'S STORY (with <br />).
  • Pill row <div className="flex flex-wrap gap-3 xl:justify-end"> mapping ["Educational", "Authentic", "Inspiring"] to <button type="button"> items with class rounded-full border border-gray-600 px-5 py-2 font-mono text-[9px] tracking-widest text-gray-300 uppercase transition-colors duration-300 hover:border-white hover:bg-white hover:text-black.

3C. Two-column panel

Preceded by a divider <div className="z-10 h-[1px] w-full bg-gray-800" />. Wrapper: <div className="z-10 flex w-full flex-col md:flex-row">.

Left panel — specimen viewer (relative flex min-h-[400px] w-full flex-col justify-between border-b border-gray-800 p-8 md:min-h-[500px] md:w-[35%] md:border-r md:border-b-0):

  • Top: <p className="relative z-10 text-xl tracking-[0.3em] text-gray-500">***</p>.
  • Center: <div className="absolute inset-0"> wrapping <AnimatePresence mode="wait"> and a SandTransitionImage keyed by chaptersData[activeChapter].image, with src/alt from the active chapter and class absolute inset-0 m-auto h-[80%] w-[80%] object-contain mix-blend-lighten.
  • Bottom — chapter counter <div className="relative z-10 flex items-center gap-2 font-mono text-[10px] tracking-widest uppercase">:
    • Animated numeral inside <span className="relative block h-[14px] w-[18px] overflow-hidden text-[#888]"> → AnimatePresence mode="wait" → motion.div keyed by activeChapter, initial={{ y: 14 }}, animate={{ y: 0 }}, exit={{ y: -14 }}, transition={{ duration: 0.4, ease: EASE }}, class absolute inset-0 leading-[14px], rendering 0{activeChapter + 1}.
    • Divider <span className="text-[#333]">/</span> and <span className="text-[#888]">05</span>.

Right panel — chapter list (w-full md:w-[65%]):

  • Top bar <div className="flex items-center justify-between border-b border-gray-800 p-8 font-mono text-[10px] tracking-widest text-gray-400 uppercase">:
    • <span>Explore the past. Understand the present.</span>
    • Animated chapter label inside <span className="relative block h-[14px] w-[72px] overflow-hidden text-right"> → AnimatePresence mode="wait" → motion.span keyed by activeChapter, initial={{ y: 14 }}, animate={{ y: 0 }}, exit={{ y: -14 }}, transition={{ duration: 0.4, ease: EASE }}, class absolute inset-0 leading-[14px], rendering Chapter 0{activeChapter + 1}.
  • Chapter list: maps chaptersData to <button type="button" onClick={() => setActiveChapter(index)}> with base class flex w-full items-center justify-between border-b border-gray-800/80 px-8 py-8 text-left transition-colors duration-300, plus text-white when active or text-[#444] hover:text-[#999] when inactive.
    • Chapter name <span className="text-2xl font-medium tracking-tight md:text-[2rem]">{chapter.name}</span>.
    • Active item shows, inside AnimatePresence, a motion.span (initial={{ opacity: 0, scale: 0.6 }}, animate={{ opacity: 1, scale: 1 }}, exit={{ opacity: 0, scale: 0.6 }}, transition={{ duration: 0.3, ease: "easeOut" }}) wrapping Lucide ArrowUpRight (size={22}, strokeWidth={1}, class text-gray-400).

3D. Bottom footer

  • Divider <div className="z-10 h-[1px] w-full bg-gray-800" />.
  • <p className="z-10 bg-[#0a0a0a] px-8 py-8 font-mono text-[10px] tracking-widest text-gray-500 uppercase">DIGGING INTO OUR PLANET'S PAST</p>.

Helper Components

SandTransitionImage — SVG-filter sand/particle dissolve

A custom component creating a sand/particle dissolve effect via an SVG filter chain, driven by requestAnimationFrame. It uses usePresence() from motion/react so it cooperates with AnimatePresence (delaying removal until the exit animation finishes via safeToRemove()). A unique filterId is generated per instance via a module-level counter held in useRef.

  • Duration: 900ms.
  • Easing: entering = quartic ease-out 1 - Math.pow(1 - t, 4); exiting = cubic Math.pow(t, 3).
  • Dissolve mapping (0 = fully resolved image, 1 = fully scattered): alpha Math.max(0, 1 - dissolve * 1.2).
  • Filter chain (feTurbulence → feDisplacementMap → feOffset → feGaussianBlur → feColorMatrix):
    • feTurbulence: type="fractalNoise", baseFrequency="1.8", numOctaves="4", result="sandNoise".
    • feDisplacementMap: in="SourceGraphic", in2="sandNoise", scale driven to 150 * dissolve, xChannelSelector="R", yChannelSelector="G", result="displaced".
    • feOffset: dx = (entering ? -30 : 30) * dissolve, dy = (entering ? -80 : 120) * dissolve, result="drifted".
    • feGaussianBlur: stdDeviation = 6 * dissolve, result="softened".
    • feColorMatrix: type="matrix", values 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${alpha} 0.
  • The hidden <svg aria-hidden="true" className="absolute h-0 w-0 overflow-hidden"> holds the <filter> (x="-50%" y="-50%" width="200%" height="200%" colorInterpolationFilters="sRGB").
  • The <img> has crossOrigin="anonymous", referrerPolicy="no-referrer", the passed className, and style={{ filter: \url(#${filterId})` }}`.
let sandFilterInstance = 0;

function SandTransitionImage({
  src,
  alt,
  className,
}: {
  src: string;
  alt: string;
  className?: string;
}) {
  const [isPresent, safeToRemove] = usePresence();
  const filterId = useRef(`sand-filter-${++sandFilterInstance}`).current;
  const displacementRef = useRef<SVGFEDisplacementMapElement>(null);
  const offsetRef = useRef<SVGFEOffsetElement>(null);
  const blurRef = useRef<SVGFEGaussianBlurElement>(null);
  const colorRef = useRef<SVGFEColorMatrixElement>(null);

  useEffect(() => {
    const DURATION = 900;
    const entering = isPresent;
    let start: number | null = null;
    let frame = 0;

    // dissolve: 0 = fully resolved image, 1 = fully scattered into sand
    const applyDissolve = (dissolve: number) => {
      const alpha = Math.max(0, 1 - dissolve * 1.2);
      displacementRef.current?.setAttribute("scale", String(150 * dissolve));
      offsetRef.current?.setAttribute("dx", String((entering ? -30 : 30) * dissolve));
      offsetRef.current?.setAttribute("dy", String((entering ? -80 : 120) * dissolve));
      blurRef.current?.setAttribute("stdDeviation", String(6 * dissolve));
      colorRef.current?.setAttribute(
        "values",
        `1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 ${alpha} 0`,
      );
    };

    const tick = (now: number) => {
      if (start === null) start = now;
      const t = Math.min(1, (now - start) / DURATION);
      const eased = entering ? 1 - Math.pow(1 - t, 4) : Math.pow(t, 3);
      applyDissolve(entering ? 1 - eased : eased);
      if (t < 1) {
        frame = requestAnimationFrame(tick);
      } else if (!entering) {
        safeToRemove();
      }
    };

    applyDissolve(entering ? 1 : 0);
    frame = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(frame);
  }, [isPresent, safeToRemove]);

  // ...renders the hidden <svg> filter + the <img> styled with filter: url(#filterId)
}

LeafIcon — custom CTA leaf glyph

A stylized leaf SVG built from 4 paths.

function LeafIcon({ className }: { className?: string }) {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
      aria-hidden="true"
    >
      <path d="M12 21V9" />
      <path d="M12 13C8.2 13 5.2 10.6 4.5 6.5C8.6 5.9 11.5 8.4 12 13Z" />
      <path d="M12 13C15.8 13 18.8 10.6 19.5 6.5C15.4 5.9 12.5 8.4 12 13Z" />
      <path d="M12 9C12 5.8 13.2 3.8 15.5 2.8" />
    </svg>
  );
}

Color Palette

  • #fcfcfc — off-white page background.
  • #111 — near-black text / logo fill.
  • #1a1a1a — CTA button background/border.
  • #0a0a0a — dark Section 3 background.
  • #888 / #333 / #444 / #999 — dark-section muted grays for counters and inactive chapter rows.
  • Tailwind gray scale gray-200 through gray-900 for borders, labels, and body text.
  • Strictly monochrome black / white / gray — no purple, indigo, or other hues.

Key Design Notes

  • Typography hierarchy: large display headings (text-[2.2rem] up to text-[5rem] / text-[4.2rem]), mono labels (text-[9px]–text-[11px]), body text (text-[12px]–text-[14px]). Inter for headings/body, JetBrains Mono for labels.
  • Spacing: broadly an 8px base system.
  • Transitions: most hover transitions run 300–700ms. The CTA slide panel and letter/heading animations use the cubic-bezier EASE = [0.16, 1, 0.3, 1] (cubic-bezier(0.16,1,0.3,1)).
  • Structure: the page is entirely one App.tsx component plus the SandTransitionImage and LeafIcon helpers in the same file.

File Structure

nhm-paleontology-landing/
├── index.html
├── package.json
└── src/
    ├── main.tsx
    ├── index.css
    └── App.tsx

Source & license

Vendored from MIT-licensed pulkitxm/claude-directory. The upstream MIT licence text ships in this template at LICENSE and must be redistributed alongside any copy of example.html or assets/.

Webfonts and full-resolution imagery are not vendored: local @font-face rules are served from the Google Fonts CDN and referenced images are downscaled. Fetch the upstream folder for the original assets.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

ZeroSum-Solutions/mishmash

Two-section scroll landing for **S.P.D**, a fictional daily-operations automation platform. Section one is a full-bleed black hero: a muted, looping period-painting video plays edge to edge behind a top-left wordmark and tagline, a top-right pill CTA, and a large right-aligned serif headline low in the frame. A cloud-plume image straddles the seam into section two, a saturated red panel holding a centered monogram, an uppercase mission line, a large script signature, two closing lines of copy, and a second looping video with a soft fade into the red. Motion is a staggered load-in fade on the hero, an IntersectionObserver reveal on the red section's content, and a scroll-linked parallax on the cloud plume — all degrading to a static, fully-visible layout under reduced motion.

ZeroSum-Solutions/mishmash

Full-screen, single-viewport (100vh, no scroll) dark hero landing page for **Asme**, a fictional no-code AI app platform. The fullscreen background is an HLS video stream from Mux, playing natively on Safari and via hls.js MediaSource on other browsers. A liquid-glass pill navbar (luminosity-blended glass with a masked `::before` gradient border) floats above an Instrument Serif hero heading and an animated email-capture CTA — "Get early access" expands to a form with a 60 ms/char typewriter placeholder, flips `ArrowRight` to `Check` on submit, and auto-resets after 4 seconds. All elements animate in on load with Motion (Framer Motion).

ZeroSum-Solutions/mishmash

A pixel-spec, dark-themed single-page marketing landing site for **Asme**, a fictional knowledge and insights platform, featuring a signature reusable `.liquid-glass` surface treatment — luminosity-blended translucent fill, 4px backdrop blur, inset top highlight, and a masked `::before` gradient border — applied consistently across the navbar pill, email capture, buttons, cards, and icon chips. The full-viewport hero loops a locally vendored `.mp4` video via a vanilla `requestAnimationFrame` opacity crossfade (fade in on `canplay`, fade out at 0.55s remaining, 100ms gap restart). Four scroll-triggered sections animate in with Framer Motion `useInView`: About, Featured Video, Innovation × Vision (video + two columns sliding from opposite sides), and Services (two glass cards with hover-zoom video). Instrument Serif display type sits against pure black throughout.

ZeroSum-Solutions/mishmash

A premium, dark-cinematic landing page for **Aura**, a fictional AI-native email client, featuring a looping fullscreen background video, a gradient-clip shiny headline, a macOS-style menu bar mockup, a realistic inbox preview, and a custom liquid-glass card treatment. The multi-section layout covers navbar, hero, menu bar, inbox mockup, feature triage, logo cloud, testimonials, pricing, and a final CTA — targeting the AI productivity app and SaaS landing page use case.

ZeroSum-Solutions/mishmash

A modern React landing page for a fictional broadcast-grade live video platform featuring a full-screen adaptive HLS video background, a glassmorphic navigation header, and hero content pinned to the bottom-left corner. Dark cinematic aesthetic with Gloock display serif, Archivo body, JetBrains Mono telemetry labels, and an aurora-green signal accent — ideal as a live streaming platform or video SaaS landing page template.

ZeroSum-Solutions/mishmash

A single-screen marketing landing page for "dot.", a calm-messaging product that links you with one anonymous peer for a single message each day. The hero is a full-screen looping background video of a phone, fronted by an animated Instrument Serif headline and a typewriter effect that types and deletes short messages ("Are you here?", "Yes, I am.", "Speak soon.") positioned to sit on the phone's on-screen display — evoking a quiet, analog rhythm. A floating pill navbar with a glinting "Link up" CTA completes the single-screen composition.

ZeroSum-Solutions/mishmash

A single-page "scrollytelling" landing page called Step Into Wonder: a 4.8-screen pinned scroll sequence where painted curtains part over a glowing crystal-cave portal, the world zooms and the portal irises open toward a sky beyond, then a giant arc of nine pastel destination cards sweeps across the closing scroll like a slow ferris wheel. Serif display headlines (Viaoda Libre) pair with a plain sans body face (Imprima) over a near-black stage, with mouse parallax on every layer and a dignified static fallback under reduced motion.

ZeroSum-Solutions/mishmash

Full landing page for the fictional AI workflow-automation platform **FlowMate** — a fixed left sidebar with a logo mark and section nav, a translucent blurred navbar, a large serif hero headline, a liquid-glass chat-composer card overlaid on a looping ambient video, a six-card feature grid, and an auto-rotating three-up cards carousel, all on an off-white minimalist palette with one indigo-violet chromatic accent.

ZeroSum-Solutions/mishmash

A single-page landing page for GroundAI, an interior-design AI product, built with TanStack Start v1 on file-based routing, React 19, TypeScript, Tailwind CSS v4, framer-motion for all animation, and lucide-react for icons. The page is composed of four stacked sections: a full-bleed autoplaying video hero with spring-animated header, expanding glass nav pill, and word-by-word animated description; a CSS marquee of partner brand wordmarks; a CraftExperiences section with a spring-driven style carousel, a skeleton-morphing chat card, and a staggered adaptable list; and a two-column testimonials block with animated word reveals.

ZeroSum-Solutions/mishmash

Produce a print-grade single-page kami (紙 / 纸) document — warm parchment canvas, ink-blue accent, serif at one weight, no italic, no cool grays. The output reads like a professional white paper or studio one-pager, not an app UI. Multilingual by design (EN · zh-CN · ja). One self-contained HTML file, zero dependencies.

ZeroSum-Solutions/mishmash

A single-page, desktop-only dark hero landing for the fictional studio **Kubric™**, built on **TanStack Start v1 + React 19 + Vite 7 + Tailwind v4** with file-based routing. Features a looping background video with a progressive 8-layer `backdrop-filter` blur at the bottom, an animated SVG logo with arc stroke-dashoffset reveals, a glass nav pill, a character-by-character headline reveal, a vertical right-side section nav, and a white "About us" card. Everything animates in on first load once the background video is ready.

ZeroSum-Solutions/mishmash

Warm, editorial single-page landing for **Velar.**, a fictional luxury real-estate brand. A deep-teal typewriter preloader gives way to a sky-backdrop hero ("Live in Irreplaceable") with a cutout building image that rises from below on load, then a scroll-driven centerpiece: as the user scrolls, that same building drifts upward and scales to 1.45x while pinning toward the bottom of a sticky black statement section with count-up stats. A hover-expand five-tile video gallery slides up over the statement section, and a bronze-gradient "Inquire" close finishes the page. Syne (display) pairs with Inter (body) throughout, on a warm off-white ground with one chromatic bronze accent.

ZeroSum-Solutions/mishmash

A full-screen, cinematic hero landing page for a creative agency called Mainframe, featuring a fixed background video that scrubs forward and backward in response to horizontal mouse movement, an AI-assistant-themed blurred intro label, a typewriter-animated headline, and a row of pill-shaped action buttons with a clipboard copy email link. The design pairs HelveticaNowDisplay-Medium headings with HelveticaNowDisplayW01-Rg body text, both vendored locally for offline use. Built with React 19, TypeScript, Vite, and Tailwind CSS v3.

ZeroSum-Solutions/mishmash

A cinematic, single-section landing hero for mėntality, a fictional mental-health resources product. The page pairs a full-bleed background video that gradient-masks into a soft `#edeef5` base with a glassmorphic, fixed navigation bar, built in React 19 + Vite and animated with Motion (formerly Framer Motion). Notable techniques include `backdrop-blur` glassmorphism, a gradient mask that blends the video top into the base color, `clamp()` fluid headline sizing, an animated SVG hamburger that morphs into an X, an inline blinking "eye/pupil" pill in the headline, and an animated `pl`/`en` language toggle. Styling is Tailwind CSS 4 via the `@tailwindcss/vite` plugin (CSS-first `@theme`, no config file), with Inter and Outfit from Google Fonts.

ZeroSum-Solutions/mishmash

A pure-black (#000) monochrome landing page for Mindloop, a newsletter and content platform, where white typography does the talking — Inter for structure and Instrument Serif italics for accent words. The seven-section page flows through a fixed glass navbar, a full-viewport MP4 hero with email capture, an AI-platform awareness section, a scroll-driven word-by-word opacity reveal, a solution feature grid with a 3:1 video panel, an HLS-streamed CTA section via hls.js (with native Safari fallback), and a minimal footer — with Framer Motion entrances and a liquid-glass CSS border effect throughout.

ZeroSum-Solutions/mishmash

Cinematic single-page landing for the fictional neural-AI platform **SynapseX**. A fixed, full-viewport background video scrubs frame-by-frame as the page scrolls and progressively blurs, sitting behind a scramble-in split-corner hero headline, a 3D-tilted cinematic paragraph reveal, and a frosted-glass horizontal metrics carousel. Pure black-and-white scaffolding is punctuated by one neon-green "synaptic" accent that ties the UI to the glowing footage underneath it.

ZeroSum-Solutions/mishmash

A dark, full-bleed landing page for Neuralyn, a fictional analytics-dashboard SaaS, featuring a full-viewport hero with a scroll-linked parallax dashboard composited over a looping background video and a scroll-driven testimonial where each word lights up as you scroll. The aesthetic is pure-black background, white type, a single italic serif accent word, and a liquid-glass tag pill. Built with React 18 + Vite and TypeScript, styled with Tailwind CSS 3 and shadcn/ui-style primitives, animated via Framer Motion (`useScroll`/`useTransform`) for scroll-linked parallax and the word-by-word color reveal, with fonts self-hosted via Fontsource.

ZeroSum-Solutions/mishmash

A single-page NFT landing site with four full-bleed sections (Hero, About, Collection, CTA) on a dark space theme. The page uses looping muted background videos, a CSS liquid-glass UI effect, a fixed grain texture overlay, and a tight color system (deep navy `#010828`, off-white `#EFF4FF`, neon green `#6FFF00`; Anton headings, Condiment cursive accents, system mono body). Showcases a three-card NFT collection grid with rarity scores and video previews.

ZeroSum-Solutions/mishmash

An integration of the `HeroGeometric` component from Kokonut UI — five blurred, gradient-filled shapes drift behind a gradient-clipped headline on a near-black `#030303` canvas, all driven by Framer Motion. The component is dropped into a proper shadcn/ui project structure and wrapped in a landing experience (floating navbar, CTAs, a live props playground, feature grid, install band) that showcases it above the fold. This animated hero section is an ideal starting point for dark-themed SaaS, design tool, or portfolio landing pages.

ZeroSum-Solutions/mishmash

A single-page space-travel landing site for "astra", with two full-height sections — a hero and a capabilities showcase — both layered over looping background videos that crossfade via a custom rAF-driven JavaScript routine (no CSS transitions). The page shares a "liquid glass" design system for all chrome (nav, chips, cards, CTAs); all text is white over full-bleed video with no dark overlay, so contrast comes entirely from the glass chrome.

相关技能