Skip to content

wistant/landing-macbook

Repository files navigation

MacBook Showcase

MacBook Showcase Landing Page - React, Vite, TypeScript, Tailwind CSS, GSAP, Three.js, Zustand Frontend Project

License: MIT Vite React TypeScript Tailwind CSS GSAP Three.js React Three Fiber Zustand

A single-page, client-side marketing-style experience inspired by Apple product pages. It combines scroll-driven storytelling (GSAP), interactive 3D (Three.js via React Three Fiber), and a small global state slice (Zustand) so learners can see how modern landing pages mix layout, motion, and WebGL without a traditional backend or REST API.


Table of contents

  1. What you will learn
  2. Keywords at a glance
  3. Tech stack & why each piece exists
  4. Project structure
  5. Features & how they work
  6. API, backend & data flow
  7. Environment variables (.env)
  8. How to run & scripts
  9. Build, preview & deploy
  10. Reusing parts in other projects
  11. Linting & type-checking
  12. Further reading
  13. Conclusion

What you will learn

  • How a Vite + React + TypeScript SPA is organized for clarity and scale.
  • How GSAP + ScrollTrigger tie scroll position to timelines (pinning, scrubbing, parallax-style motion).
  • How React Three Fiber mounts a Three.js scene inside React and loads GLTF models with drei helpers.
  • How Zustand shares a few values (color, scale, screen video texture) between UI controls and 3D materials.
  • How Tailwind CSS v4 (via @tailwindcss/vite) keeps styling co-located with components using @layer rules in src/index.css.

Keywords at a glance

Keyword / topic Short meaning in this repo
SPA One HTML shell; all routes are client-side (no Next.js router).
ScrollTrigger GSAP plugin: run animations based on scroll position.
R3F React renderer for Three.js (<Canvas>, <mesh>, hooks).
drei Helpers: useGLTF, useVideoTexture, Environment, etc.
GLTF / GLB 3D model format; .glb is binary, used for MacBook meshes.
Zustand Minimal global store; no Redux boilerplate.
Vite Fast dev server & optimized production bundles.
Tailwind @theme Design tokens (fonts, colors) declared in CSS for v4.

Tech stack & why each piece exists

Technology Role here
Vite 7 Dev server, HMR, production build, asset pipeline.
React 19 UI composition, hooks, concurrent-friendly patterns.
TypeScript Types for props, refs, GLTF results, and store shape.
Tailwind CSS 4 Utility classes + @layer components for section layout (see index.css).
GSAP 3 Timelines, easing, ScrollTrigger for scroll-synced motion.
@gsap/react useGSAP hook with proper cleanup in React.
three + R3F + drei 3D scene, models, lights, video textures on the laptop screen.
react-responsive useMediaQuery for mobile vs desktop tuning (e.g. model scale).
clsx Conditional class names in JSX (e.g. active swatches).
Zustand color, scale, texture + setters for product viewer & features.

Note: This is not a Next.js appβ€”there is no app/ router, no getServerSideProps, and no built-in API routes. Everything ships as static HTML/JS/CSS plus files under public/.


Project structure

macbook-ui/
β”œβ”€β”€ public/                 # Static assets (served as-is at /)
β”‚   β”œβ”€β”€ fonts/              # Custom OTF faces
β”‚   β”œβ”€β”€ models/             # MacBook GLB / transformed GLB
β”‚   β”œβ”€β”€ videos/             # Hero, game, feature loops
β”‚   β”œβ”€β”€ robots.txt
β”‚   └── …png / .svg         # Icons, performance art, etc.
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.tsx            # React root + StrictMode
β”‚   β”œβ”€β”€ App.tsx             # Registers ScrollTrigger; composes sections
β”‚   β”œβ”€β”€ index.css           # Tailwind import + @layer component styles
β”‚   β”œβ”€β”€ vite-env.d.ts       # Vite client types (e.g. CSS modules)
β”‚   β”œβ”€β”€ constants/index.ts  # Nav links, features copy, image lists, etc.
β”‚   β”œβ”€β”€ store/index.ts      # Zustand Macbook store
β”‚   β”œβ”€β”€ types/macbookGltf.ts# Shared typing helper for GLTF + meshes
β”‚   └── components/
β”‚       β”œβ”€β”€ NavBar.tsx
β”‚       β”œβ”€β”€ Hero.tsx
β”‚       β”œβ”€β”€ ProductViewer.tsx
β”‚       β”œβ”€β”€ Showcase.tsx
β”‚       β”œβ”€β”€ Performance.tsx
β”‚       β”œβ”€β”€ Features.tsx
β”‚       β”œβ”€β”€ Highlights.tsx
β”‚       β”œβ”€β”€ Footer.tsx
β”‚       β”œβ”€β”€ models/         # Macbook.tsx, Macbook-14.tsx, Macbook-16.tsx
β”‚       └── three/          # StudioLights.tsx, ModelSwitcher.tsx
β”œβ”€β”€ docs/                   # Internal design / guardrail notes (optional read)
β”œβ”€β”€ index.html              # Entry HTML + SEO + preload hints
β”œβ”€β”€ vite.config.js          # Plugins, manualChunks for heavy vendors
β”œβ”€β”€ vercel.json             # Security headers + long cache for /assets/*
β”œβ”€β”€ tsconfig*.json          # TypeScript project references
β”œβ”€β”€ eslint.config.js        # Flat ESLint + TypeScript rules
β”œβ”€β”€ LICENSE                 # MIT
└── README.md               # This file

Features & how they work

1. NavBar

  • Static header: logo, faux nav links, search/cart icons.
  • Styles live under @layer components { header { … } } in src/index.css.

2. Hero

  • Title image + hero MP4 (playbackRate bumped in useEffect).
  • Plain Buy button (no server actionβ€”purely presentational).

3. ProductViewer

  • <Canvas> from @react-three/fiber with StudioLights + ModelSwitcher.
  • Zustand drives swatches (14β€³ / 16β€³) and body color; PresentationControls + GSAP fade/slide between two GLTF groups.

4. Showcase

  • Full-width video + masked logo; ScrollTrigger pin + scrub timeline on desktop to sync mask scale and text opacity.

5. Performance

  • Collage of performance images with a scrubbed GSAP timeline repositioning images on desktop; paragraph fades in on scroll.

6. Features

  • Pinned feature canvas: MacBook model rotates on scroll; feature videos preloaded in useEffect; texture swaps coordinated with .box1….box5 opacity tweens.

7. Highlights

  • Masonry-style cards; GSAP reveals columns on scroll (different trigger on mobile vs desktop).

8. Footer

  • Static links and copyright lineβ€”no fetch.

GSAP registration (once at app level):

import gsap from "gsap";
import { ScrollTrigger } from "gsap/all";

gsap.registerPlugin(ScrollTrigger);

Zustand store (shared 3D + UI state):

import { create } from "zustand";

const useMacbookStore = create<MacbookState>()((set) => ({
  color: "#2e2c2e",
  setColor: (color) => set({ color }),
  scale: 0.08,
  setScale: (scale) => set({ scale }),
  texture: "/videos/feature-1.mp4",
  setTexture: (texture) => set({ texture }),
  reset: () =>
    set({ color: "#2e2c2e", scale: 0.08, texture: "/videos/feature-1.mp4" }),
}));

export default useMacbookStore;

API, backend & data flow

Question Answer
REST / GraphQL API? None. All content is static JSON/arrays in src/constants/index.ts or hardcoded JSX.
Server-side rendering? No. First paint is the built SPA; crawlers see index.html meta + shell.
Where do videos/models live? Under public/β€”URLs like /videos/hero.mp4 resolve at runtime from the deployed origin.
Authentication? None.

If you later add a real backend, you would typically introduce fetch calls, optional React Query / TanStack Query, and environment-based base URLs (see Environment variables).


Environment variables (.env)

You do not need any .env file to run or build this projectβ€”there are no secret keys, database URLs, or third-party API tokens in the codebase today.

Optional pattern for future work (Vite convention: only variables prefixed with VITE_ are exposed to client code):

  1. Create .env.local (gitignored) in the project root:

    # .env.local (example β€” not required for this repo)
    VITE_PUBLIC_APP_NAME=MacBook Pro Landing
  2. Read in code (after you actually need it):

    const appName =
      import.meta.env.VITE_PUBLIC_APP_NAME ?? "MacBook Pro Landing Page";
  3. Never commit real secrets. Use Vercel/hosting Environment Variables UI for production values.


How to run & scripts

Prerequisites: Node.js 20+ (LTS recommended) and npm.

# Install dependencies
npm install

# Start dev server (default http://localhost:5173)
npm run dev
Script What it does
npm run dev Vite dev server with hot reload.
npm run build TypeScript-aware production build to dist/.
npm run preview Serves the production build locally for testing.
npm run lint ESLint over src/ (and config files).
npm run type-check tsc -b β€” full project type check, no emit.

Build, preview & deploy

npm run build
npm run preview

Vercel (current demo host): connect the Git repo or deploy the dist/ output as a static site. vercel.json adds security headers and long-lived caching for hashed assets under /assets/. public/robots.txt guides crawlers.


Reusing parts in other projects

Piece How to reuse
Section components Copy a component + matching @layer block from index.css, or move styles into modules.
Zustand store Extract store/index.ts into a package or lib/store in a monorepo; keep types alongside.
R3F canvas Wrap <Canvas> in Suspense; preload GLBs with useGLTF.preload in the same module as use.
GSAP ScrollTrigger Always registerPlugin once; kill/refresh triggers on route change if you add a router later.
Constants Replace src/constants/index.ts with CMS/API-driven data when you outgrow static arrays.

Linting & type-checking

npm run lint
npm run type-check

ESLint uses the flat config (eslint.config.js) with TypeScript ESLint, React Hooks, and React Refresh rules suited for Vite.


Further reading


Conclusion

MacBook UI is a focused learning sandbox: one scroll narrative, two major β€œwow” layers (motion + 3D), and a tiny amount of shared state. It intentionally avoids backend complexity so you can study layout β†’ animation β†’ WebGL in isolation, then bolt on APIs or a meta-framework when your product needs them.


License

This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.

Happy Coding! πŸŽ‰

This is an open-source project - feel free to use, enhance, and extend this project further!

If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://www.wistant.dev.

Enjoy building and learning! πŸš€

Thank you! 😊


About

A single-page, client-side marketing-style experience inspired by Apple product pages. It combines scroll-driven storytelling (GSAP), interactive 3D (Three.js via React Three Fiber), and a small global state slice (Zustand) so learners can see how modern landing pages mix layout, motion, and WebGL without a traditional backend or REST API.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors