A scroll-driven cinematic landing page themed around Stark Industries and the Mark LXXXV suit. Scroll to scrub through two frame-by-frame canvas sequences, reveal iconic Tony Stark dialogue, and explore a HUD-style diagnostics panel — all wrapped in smooth Lenis scrolling, Framer Motion transitions, and a dark gold-accent design system.
Fan art / proof of concept. Not affiliated with Marvel or Disney. No commercial use.
| Section | What happens |
|---|---|
| Hero | 169-frame Mark LXXXV suit-up sequence driven by scroll |
| Cinematic Reveal | Second 169-frame Endgame sequence with “Inevitable → Iron Man” text swap |
| Systems Nominal | Animated telemetry readouts and closing quote |
| Footer | Suit archive grid and build metadata |
- Scroll-scrubbed canvas animation — Two independent sticky sections map scroll progress to 169 JPG frames each, rendered on
<canvas>with cover-fit scaling and device-pixel-ratio support. - Timed dialogue & beat cards — Quotes fade in/out at configurable scroll thresholds (
src/lib/hero.ts,src/lib/cinematic.ts). - HUD chrome — Corner brackets, arc-reactor power readout, sequence counters, and progress bars that track scroll position.
- Smooth scrolling — Lenis for buttery wheel scrolling.
- Scroll-triggered motion — Framer Motion stagger animations in the Systems section.
- Responsive layout — Mobile-specific dialogue stacking, shorter scroll heights on smaller viewports, and adaptive canvas zoom.
- Loading states — Boot screens with progress bars while all frames preload.
| Layer | Tools |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19, TypeScript |
| Styling | Tailwind CSS 4, custom CSS variables & glassmorphism utilities |
| Animation | Framer Motion, Lenis |
| Icons | @phosphor-icons/react |
| Fonts | Geist Sans & Geist Mono via next/font |
- Node.js 18.18 or later
- npm, pnpm, yarn, or bun
npm installnpm run devOpen http://localhost:3000. The page hot-reloads as you edit files under src/.
npm run build
npm startnpm run lintIronMan/
├── public/
│ ├── frames/ # Hero sequence — frame_0001.jpg … frame_0169.jpg
│ └── frames2/ # Cinematic sequence — frame_0001.jpg … frame_0169.jpg
├── src/
│ ├── app/
│ │ ├── layout.tsx # Root layout, fonts, SmoothScrollProvider
│ │ ├── page.tsx # Single-page composition
│ │ └── globals.css # Tailwind, theme tokens, scroll heights, grain overlay
│ ├── components/
│ │ ├── providers/
│ │ │ └── SmoothScrollProvider.tsx
│ │ ├── sections/
│ │ │ ├── Hero.tsx
│ │ │ ├── CinematicReveal.tsx
│ │ │ ├── SystemsNominal.tsx
│ │ │ └── Footer.tsx
│ │ └── ui/
│ │ ├── Navbar.tsx
│ │ ├── HudFrame.tsx
│ │ ├── EyebrowBadge.tsx
│ │ └── AnimatedSection.tsx
│ └── lib/
│ ├── hero.ts # Hero frame paths, dialogues, fade constants
│ └── cinematic.ts # Cinematic frame paths, beats, fade constants
├── next.config.ts
├── tsconfig.json
└── package.json
Each cinematic section is a tall container (.scroll-animation, 300–400vh depending on breakpoint) with a sticky inner viewport. On scroll:
- Scroll progress (0 → 1) is calculated from the section’s position.
- Progress maps to a frame index (
0 … 168). - The matching image is drawn to a full-viewport canvas.
This pattern is shared by Hero and CinematicReveal, with separate frame directories and content configs.
Dialogue and beat cards use normalized scroll thresholds:
// Example from src/lib/hero.ts
{ id: "d1", show: 0.1, hide: 0.3, quote: "...", speaker: "Tony Stark", film: "IRON MAN — 2008" }Adjust show / hide values to shift when cards appear during a sequence.
CSS custom properties in globals.css define the palette:
| Token | Value | Usage |
|---|---|---|
--background |
#0a0a0b |
Page background |
--foreground |
#e4e4e7 |
Primary text |
--accent |
#d4a22f |
Arc-reactor gold |
--muted |
#71717a |
Secondary text |
Utility classes like .card-surface and .grain add frosted glass panels and a subtle film-grain overlay.
Both sequences require 169 numbered JPEG frames each:
- Hero:
public/frames/frame_0001.jpg…frame_0169.jpg - Cinematic:
public/frames2/frame_0001.jpg…frame_0169.jpg
Frame counts are defined in src/lib/hero.ts (FRAME_COUNT) and src/lib/cinematic.ts (CINE_FRAME_COUNT). If you replace sequences, keep filenames zero-padded to four digits and update the count constants to match.
Deploy like any standard Next.js app. Vercel is the simplest option:
- Push the repo to GitHub.
- Import the project in Vercel.
- Deploy — no extra environment variables required.
Because frame assets live in public/, they are served statically at build time. Ensure both frame directories are included in the repository (or your CDN) for production.
Update metadataBase in src/app/layout.tsx from http://localhost:3000 to your production URL for correct Open Graph / metadata URLs.
| Command | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Create optimized production build |
npm start |
Serve production build |
npm run lint |
Run ESLint (Next.js core-web-vitals + TypeScript rules) |
This project is fan art and a technical showcase. Iron Man, Tony Stark, J.A.R.V.I.S., and related names are trademarks of Marvel / Disney. No affiliation is implied. Not for commercial use.
Made with 💖 by Amjad Imdad
✨ Star this repo if you found it cool! ✨
Contributions, feedback & PRs are always welcome 🚀