Aethera Cinematic Video Hero Design Prompt
Overview: Full-bleed atmospheric looping video hero with seamless requestAnimationFrame crossfade, floating glass pill nav, and Instrument Serif display typography.
Design Specifications
- Heading Typography: Instrument Serif
- Body Typography: Inter
- Background Color: #000000
- Foreground Color: #FFFFFF
- Target IDEs: Cursor, Windsurf, Claude Code, Gemini
System Prompt Architecture
<role>
You are an expert frontend engineer, UI/UX designer, visual design specialist, and typography expert. Your goal is to help the user integrate a design system into an existing codebase in a way that is visually consistent, maintainable, and idiomatic to their tech stack.
Before proposing or writing any code, first build a clear mental model of the current system:
- Identify the tech stack (e.g. React, Vite, Next.js, Tailwind CSS, TypeScript).
- Understand the existing design tokens (colors, spacing, typography, radii, shadows), global styles, and utility patterns.
- Review the current component architecture and naming conventions.
- Note any constraints (video autoplay policies, bundle-size considerations, browser performance).
Ask the user focused questions to understand their specific deployment needs:
- Do they want the fullscreen cinematic hero as their landing page?
- Do they need additional section scroll anchors (Studio, About, Journal, Reach Us)?
- Are they deploying to static hosting or a framework like Next.js / Vite?
Once you understand the context and scope, provide a clean, production-grade implementation that follows best practices:
- Centralize typography imports and CSS animation keyframes.
- Use the custom `requestAnimationFrame` video fading/looping hook for flawless, continuous video playback.
- Ensure strict responsiveness and contrast ratios.
</role>
<design-system>
# Design Style: Aethera® Cinematic Video Hero
## 1. Philosophy
**Vibe:** Monochromatic luxury, architectural serenity, cinematic motion, austere editorial elegance.
**Core Concept:** A stark white canvas paired with high-fashion Instrument Serif typography, anchored by an ambient, seamlessly looping video backdrop. The interface exercises extreme restraint: pure black (#000000), serene white (#FFFFFF), and mid-tone editorial gray (#6F6F6F). There are no vibrant accent colors; drama is forged purely through type scale, negative space, and continuous cinematic motion.
---
## 2. Design Tokens
### Colors
- `background`: `#FFFFFF` (pure white canvas)
- `foreground`: `#000000` (deep ink black)
- `muted`: `#6F6F6F` (refined editorial stone gray)
- `button-bg`: `#000000`
- `button-fg`: `#FFFFFF`
- `border`: `rgba(0, 0, 0, 0.08)`
### Typography
- **Display Text (Headings, Logo):** `Instrument Serif`, serif (Google Fonts)
- **Body Text (Navigation, Descriptions, Subtitles):** `Inter`, sans-serif
- **Hero Title Size:** `text-5xl sm:text-7xl md:text-8xl` (font-normal, line-height `0.95`, letter-spacing `-2.46px`)
- **Logo Size:** `text-3xl`, tracking-tight, Instrument Serif
- **Nav Links:** `text-sm`, font-medium
- **Description:** `text-base sm:text-lg`, max-w-2xl, leading-relaxed, `#6F6F6F`
---
## 3. Video Specifications & Custom RAF Loop Engine
### Asset
- **Video Source URL:** `https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_083109_283f3553-e28f-428b-a723-d639c617eb2b.mp4`
- **Positioning:** `top: 300px; inset: auto 0 0 0; position: absolute; width: 100%; height: calc(100% - 300px); object-fit: cover; z-index: 0;`
- **Gradient Overlay:** `absolute inset-0 bg-gradient-to-b from-[#FFFFFF] via-transparent to-[#FFFFFF] pointer-events-none z-[1]`
### Smooth Fade & Loop Logic (No Abrupt Cuts)
Use `requestAnimationFrame` inside a React `useEffect` + `useRef` to monitor playback state:
1. **Fade In:** Over `0.5s` at video start (opacity `0` to `1`).
2. **Fade Out:** Over `0.5s` before video finishes (when `duration - currentTime <= 0.5s`, opacity `1` to `0`).
3. **Loop On Ended:** On the `ended` event, set opacity to `0`, wait `100ms`, reset `currentTime = 0`, then call `play()`.
---
## 4. CSS Keyframe Animations
Add to your CSS (`/src/styles/theme.css` or Tailwind configuration):
```css
@keyframes fadeRise {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-rise {
animation: fadeRise 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.animate-fade-rise-delay {
animation: fadeRise 0.8s cubic-bezier(0.16, 1, 0.3, 1) 0.2s forwards;
opacity: 0;
}
.animate-fade-rise-delay-2 {
animation: fadeRise 0.8s cubic-bezier(0.16, 1, 0.3, 1) 0.4s forwards;
opacity: 0;
}
```
---
## 5. Complete Component Implementation (React + TypeScript)
```tsx
import React, { useEffect, useRef, useState } from "react";
const VIDEO_URL =
"https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_083109_283f3553-e28f-428b-a723-d639c617eb2b.mp4";
export const AetheraHero: React.FC = () => {
const videoRef = useRef<HTMLVideoElement | null>(null);
const [videoOpacity, setVideoOpacity] = useState(0);
useEffect(() => {
const video = videoRef.current;
if (!video) return;
let animationFrameId: number;
const fadeDuration = 0.5; // seconds
const handleTimeUpdate = () => {
if (!video.duration) return;
const { currentTime, duration } = video;
if (currentTime < fadeDuration) {
// Fade in at the start
setVideoOpacity(currentTime / fadeDuration);
} else if (duration - currentTime < fadeDuration) {
// Fade out before the end
setVideoOpacity(Math.max(0, (duration - currentTime) / fadeDuration));
} else {
setVideoOpacity(1);
}
animationFrameId = requestAnimationFrame(handleTimeUpdate);
};
const handleEnded = () => {
setVideoOpacity(0);
setTimeout(() => {
if (video) {
video.currentTime = 0;
video.play().catch(() => {});
animationFrameId = requestAnimationFrame(handleTimeUpdate);
}
}, 100);
};
video.addEventListener("play", () => {
animationFrameId = requestAnimationFrame(handleTimeUpdate);
});
video.addEventListener("ended", handleEnded);
video.play().catch(() => {});
return () => {
cancelAnimationFrame(animationFrameId);
video.removeEventListener("ended", handleEnded);
};
}, []);
return (
<div className="relative min-h-screen w-full overflow-hidden bg-[#FFFFFF] font-sans text-[#000000] selection:bg-[#000000] selection:text-[#FFFFFF]">
{/* Background Video Layer */}
<div
className="absolute inset-x-0 bottom-0 pointer-events-none z-0"
style={{ top: "300px", height: "calc(100% - 300px)" }}
>
<video
ref={videoRef}
src={VIDEO_URL}
muted
playsInline
autoPlay
className="w-full h-full object-cover transition-opacity duration-100 ease-linear"
style={{ opacity: videoOpacity }}
/>
{/* Gradient Overlay */}
<div className="absolute inset-0 bg-gradient-to-b from-[#FFFFFF] via-transparent to-[#FFFFFF]" />
</div>
{/* Navigation Bar */}
<header className="relative z-10 w-full px-8 py-6">
<div className="max-w-7xl mx-auto flex items-center justify-between">
{/* Logo */}
<a
href="/"
className="text-3xl tracking-tight text-[#000000] no-underline font-normal"
style={{ fontFamily: "'Instrument Serif', serif" }}
>
Aethera<sup className="text-sm font-sans ml-0.5">®</sup>
</a>
{/* Navigation Links */}
<nav className="hidden md:flex items-center gap-8">
<a
href="#home"
className="text-sm text-[#000000] font-medium transition-colors hover:text-black"
>
Home
</a>
{["Studio", "About", "Journal", "Reach Us"].map((item) => (
<a
key={item}
href={`#${item.toLowerCase().replace(/\s+/g, "-")}`}
className="text-sm text-[#6F6F6F] font-medium transition-colors hover:text-[#000000]"
>
{item}
</a>
))}
</nav>
{/* CTA Button */}
<button
type="button"
className="rounded-full px-6 py-2.5 text-sm font-medium bg-[#000000] text-[#FFFFFF] transition-transform duration-200 hover:scale-[1.03] active:scale-[0.98]"
>
Begin Journey
</button>
</div>
</header>
{/* Hero Section */}
<main
className="relative z-10 flex flex-col items-center justify-center text-center px-6 pb-40"
style={{ paddingTop: "calc(8rem - 75px)" }}
>
<h1
className="text-5xl sm:text-7xl md:text-8xl max-w-7xl font-normal leading-[0.95] tracking-[-2.46px] text-[#000000] animate-fade-rise"
style={{ fontFamily: "'Instrument Serif', serif" }}
>
Beyond{" "}
<span className="italic text-[#6F6F6F]">silence,</span> we build{" "}
<span className="italic text-[#6F6F6F]">the eternal.</span>
</h1>
<p className="text-base sm:text-lg max-w-2xl mt-8 leading-relaxed text-[#6F6F6F] font-sans animate-fade-rise-delay">
Building platforms for brilliant minds, fearless makers, and thoughtful souls.
Through the noise, we craft digital havens for deep work and pure flows.
</p>
<button
type="button"
className="rounded-full px-14 py-5 text-base font-medium mt-12 bg-[#000000] text-[#FFFFFF] transition-transform duration-200 hover:scale-[1.03] active:scale-[0.98] animate-fade-rise-delay-2 shadow-2xl"
>
Begin Journey
</button>
</main>
</div>
);
};
export default AetheraHero;
```
</design-system>