Skip to content

ASTRICKK/PorscheLab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 

Repository files navigation

🏎️ PorscheLab

Enterprise-Grade Real-Time 3D Car Configurator — Powered by WebGL, React Three Fiber & GSAP

React Three.js TypeScript Vite Zustand GSAP Netlify AI FPS Mobile


PorscheLab — Real-Time 3D Porsche Configurator
PorscheLab — UX/UI Overview & Lighthouse 100 Score



🏆 Lighthouse Score: 100 · Performance · Accessibility · Best Practices · SEO


🏆 Recognition & Achievements

🏅 Achievement 📌 Detail
🔥 Officially Reposted by Three.js Featured directly by the official Three.js account — recognized by the core WebGL community as a standout real-world implementation
👍 190+ Likes on LinkedIn Organically reached 190+ reactions on LinkedIn, driving significant professional engagement across the web & 3D development community

Being officially featured by Three.js — the foundational library powering this entire project — is a rare honor that validates the depth of the WebGL engineering involved. The LinkedIn reception confirms real-world interest from both technical and business audiences.


🚀 What is PorscheLab?

PorscheLab is a photorealistic, browser-native 3D car configurator that brings dealership-grade automotive visualization directly into any web browser — no app download, no plugins, no compromise.

Built entirely by hand with 0% AI-generated code, every line of this codebase reflects intentional engineering decisions — from handcrafted 6-DOF camera keyframe arrays per vehicle, to a 13-channel audio engine that responds to every user interaction in real time.

Business Value: In an era where automotive brands compete fiercely for customer attention online, PorscheLab demonstrates what a next-generation digital showroom looks like — immersive, interactive, and accessible from any device at 60–120 FPS, including mobile.


� Business Interaction Concept

PorscheLab is more than a technical showcase. It represents a digital-first sales and engagement model for the premium automotive industry:

Business Use Case How PorscheLab Enables It
🏪 Virtual Dealership Customers explore any model, any angle, any color — without stepping into a showroom
🎨 Real-Time Personalization Live paint, metalness & roughness controls let buyers configure their dream car instantly
📱 Omnichannel Reach Full mobile support means the configurator works on any device, anywhere
🌍 Environment Storytelling 8 cinematic HDRI environments let brands present cars in aspirational contexts
🔊 Sensory Brand Experience Spatial audio tied to every interaction (door, engine, spray) reinforces emotional connection
🏠 Interior Deep-Dive Buyers can step inside any car, switch seats, and inspect the cockpit — virtually
📊 Model Comparison Switch between 7 distinct Porsche lineups in seconds with seamless cinematic transitions
🔗 Embedded Spec Sheet Right-panel iframe links directly to official Porsche product pages per model

⚡ Key Highlights

┌─────────────────────────────────────────────────────────────┐
│   🤖  AI-Generated Code          →   0%   (fully handcrafted) │
│   🎮  Rendering Performance      →   60–120+ FPS             │
│   📱  Mobile Support             →   100% (touch, pinch, UI) │
│   🏎️  Porsche Models Included    →   7 photorealistic models  │
│   🎨  Color Configurations       →   16 presets + custom hex  │
│   🌅  HDRI Environments          →   8 cinematic scenes       │
│   🔊  Audio Channels             →   13 spatially-aware sounds│
│   🏆  Lighthouse Score           →   100 across all metrics   │
└─────────────────────────────────────────────────────────────┘

🖼️ Visual Showcase

🎬 The Experience — First Look & Performance

The moment a user lands on PorscheLab, they're greeted with a cinematic loading sequence followed by a scroll-driven brand narrative — immersing them into Porsche's history before they ever touch the configurator.

PorscheLab is also engineered to perform at the highest standard — achieving 100/100 across all Lighthouse metrics (Performance · Accessibility · Best Practices · SEO), proving that stunning 3D experiences and web performance are not mutually exclusive.

See the cover images above for the full-screen brand experience and UX/UI overview.


� Exterior Inspection — 360° Full Control

Users aren't passive observers. PorscheLab hands total physical control of the camera — drag to orbit, pinch to zoom, tap the inspect icon to jump to pre-choreographed cinematic viewpoints. Every angle, every detail.

Exterior View — Orbit & Color Change Active

The user can freely orbit around the vehicle in full 3D. The color picker panel is open at the bottom — 16 curated Porsche paint colors + custom hex input with live PBR paint update.


🎨 Real-Time Paint — Applied

One click on a color swatch triggers a GSAP-animated smooth color transition directly on the car's PBR material in the WebGL scene — no page reload, no delay. The spray-shake sound fires simultaneously for full sensory feedback.

Exterior View — New Color Applied

New paint color applied in real time. Metalness and roughness sliders allow further surface customization — from matte to mirror-chrome — all bound to per-car Zustand state.


🔙 Rear Perspective — True 3D Depth

Because every model is a fully realized 3D asset with complete geometry on all sides, users can navigate to the rear of the vehicle — demonstrating that this is genuine spatial content, not a billboard or turntable illusion.

Rear Exterior View

Rear-view perspective accessed via the Exterior Inspect cycling button. Each of the 8 keyframe positions is hand-calibrated per model for the most flattering camera angle.


🏠 Interior Mode — Cockpit Immersion

A single tap on the steering wheel icon triggers the door-close sound effect, locks the camera into interior mode, and begins a guided cockpit tour. The camera constraints change entirely — close-range, restricted orbit, designed to feel like you're sitting in the seat.

Interior Cockpit View

Interior inspection mode active. Camera constraints shift to micro-range (minDistance: 0.05) to simulate being seated inside the vehicle. Interior ambient audio plays automatically.


🌅 Environment Switcher — 8 Cinematic Scenes

The environment panel gives users access to 8 real-world HDRI captures streamed live from Polyhaven at resolution-optimized quality (2K on mobile, 4K on desktop). The environment changes the entire lighting of the scene — affecting reflections, shadows, and mood.

Environment Selector Panel

Environment panel open showing all 8 HDRI options with thumbnail previews. Each environment has individually tuned ground projection parameters for interior vs. exterior views.


📋 Model Detail Panel — Specs at a Glance

The left hamburger menu reveals a model information panel displaying the car's real-world specifications — 0-100 km/h time, top speed, power output (kW + PS), and price. A direct link to the official Porsche product page is embedded as an iframe.

Model Detail & Spec Panel

Model detail drawer open. Specs pulled from the Zustand porscheModelList store. The iframe at the bottom loads the live Porsche Thailand product page for the current model.


🪑 Interior — Rear Seat Zone

Interior mode isn't limited to the driver's seat. Users can cycle through up to 5 interior camera positions per vehicle — including rear passenger seats — for a full cabin inspection experience.

Interior — Rear Seat Zone, Model A

Rear cabin perspective. The interior inspect mode cycles through 5 hand-placed camera keyframes, each giving a distinct spatial understanding of the vehicle's interior layout.

Interior — Rear Seat Zone, Model B

Same interior inspection applied to a different Porsche model — demonstrating that every vehicle in the lineup has independently configured interior camera paths.


🔄 Car Model Switcher

The change-car panel displays all available Porsche models with thumbnail previews. Selecting a model triggers a lazy-load swap — the old model unmounts, the new GLTF component is code-split imported and rendered, with camera position restored to the hero exterior view.

Car Model Switcher Panel

Model selection panel showing all 7 Porsche models. Each entry displays real performance data. Switching models is seamless — Zustand state resets all inspect modes automatically.


�️ The Full Lineup — All 7 Models

PorscheLab covers Porsche's complete current-era lineup — from EV to hypercar. Every model has been manually optimized with calibrated PBR material parameters to look photorealistic under any HDRI environment.

Porsche 911 Turbo S

Porsche Taycan

Porsche 918 Spyder

Porsche 911 GT3 RS

Porsche Cayenne

Porsche 718 Cayman

All 7 models share the same camera system, audio engine, and UI — but each has independently calibrated metalness/roughness values, camera keyframe sets, and interior configurations.


📱 Mobile — Full Performance, Zero Compromise

Every interaction — touch-to-orbit, pinch-to-zoom, tap-to-inspect, color swatches, spec panels — works identically on mobile. HDRI resolution auto-scales to 2K on smaller viewports. FPS stays at 60–120 even on mid-range phones.

Mobile Performance — Smooth Rendering

Mobile screenshot composite showing smooth real-time rendering on phone screens. Touch controls mirror desktop interactions. The responsive layout adapts camera FOV (65° on mobile vs 50° on desktop) for optimal framing.


📋 Table of Contents

  1. Technical Project Overview
  2. Technology Architecture
  3. System Architecture Diagram
  4. Rendering Pipeline
  5. Scene Initialization Sequence
  6. State Management Architecture
  7. Camera Control System
  8. Audio Engine Architecture
  9. 3D Model Pipeline
  10. Homepage Scroll Animation System
  11. Configurator UI Layer
  12. HDR Environment System
  13. Deployment Pipeline
  14. Project Structure
  15. Getting Started
  16. Performance Considerations

� Technical Project Overview

PorscheLab tackles several notoriously difficult engineering challenges simultaneously:

Challenge Solution
High-polygon GLTF models (multiple) in browser Lazy-loaded Suspense with per-car code splitting
Physically-based rendering at 60fps Tuned PBR material params + low-res post-process passes
Cinematic camera fly-throughs without jank GSAP timeline-driven CameraControls choreography
Seamless exterior ↔ interior camera transitions Per-model 3D LookAt keyframe configs stored in Zustand
Immersive spatial audio that mirrors scene state Pre-loaded 13-track Web Audio engine with state gating
Scroll-driven homepage narrative with pinned sections GSAP ScrollTrigger + SplitText word-by-word reveals
Real-time PBR paint override with metalness/roughness Per-car MeshStandardMaterial binding through Zustand
HDR environment switching (8 environments) Dynamic .hdr streaming from Polyhaven CDN

🌐 Live Demo

Deployed on Netlify with SPA redirect rules and Node 24 build environment.

Click here


🏗️ Technology Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                        PorscheLab Stack                             │
├──────────────────┬──────────────────────────────────────────────────┤
│  Presentation    │  React 19 + TypeScript 5.8 + React Router 7      │
│  3D Engine       │  Three.js r176 + React Three Fiber 9             │
│  3D Utilities    │  @react-three/drei (CameraControls, Environment, │
│                  │  AccumulativeShadows, useProgress)               │
│  Post-Processing │  @react-three/postprocessing + postprocessing    │
│                  │  (Bloom, Vignette, BlendFunction)                │
│  Animation       │  GSAP 3 + @gsap/react + ScrollTrigger + SplitText│
│                  │  + TextPlugin                                    │
│  State           │  Zustand 5 (3 independent stores)               │
│  Audio           │  Web Audio API (HTMLAudioElement, 13 tracks)     │
│  3D Assets       │  GLTF/GLB (gltfjsx-generated React components)   │
│  Build           │  Vite 6 (ESM, code-splitting, lazy imports)      │
│  Deploy          │  Netlify (Node 24, SPA redirects)               │
└──────────────────┴──────────────────────────────────────────────────┘

🗺️ System Architecture Diagram

graph TD
    A["🌐 Browser Entry: main.tsx"]:::entry --> B["BrowserRouter"]
    B --> C["Route: / → Homepage"]
    B --> D["Route: /configurator → ProtectedPorscheConfigurator"]
    B --> E["Route: * → Redirect /"]

    C --> F["Homepage.tsx"]
    F --> G["HomepageMain.tsx (lazy)"]
    G --> H["Loading Screen\n(4-layer slide-out animation)"]
    G --> I["NavigateBar.tsx"]
    G --> J["HomepageContent"]
    J --> J1["HomepageHero\n(Video BG)"]
    J --> J2["HomepageHistorySection\n(GSAP Pin + SplitText)"]
    J --> J3["HomepagePresentSection\n(Parallax Image Reveal)"]
    J --> J4["HomepageChooseCar\n(Model Picker Grid)"]
    G --> K["InitLogic.tsx\n(GSAP ScrollTrigger Orchestrator)"]

    D --> L["ProtectedPorscheConfigurator.tsx\n(Route Guard)"]
    L --> M["PorscheConfigurator.tsx\n(Main 3D Scene)"]

    M --> N["NavigateBarConfigurator.tsx\n(2D UI Overlay)"]
    M --> O["R3F Canvas"]
    O --> P["CameraControls\n(@react-three/drei)"]
    O --> Q["DynamicCarChanging.tsx\n(Lazy Model Switcher)"]
    O --> R["MemoLighterAccumulativeShadows\n(Shadow Baking)"]
    O --> S["Environment\n(HDR Streaming)"]
    O --> T["InitialConfiguratorLogics.tsx\n(Camera Choreography)"]
    O --> U["EffectComposer\n(Bloom + Vignette)"]
    M --> V["LoadingHomeScreen.tsx\n(Overlay + Progress)"]
    M --> W["InitLogicNavConfig.tsx\n(2D UI Entrance Animation)"]

    subgraph STORES ["⚙️ Zustand State Stores"]
        X["usePorscheConfiguratorSettings\n• 7 car configs\n• PBR material params\n• Camera keyframes\n• Color palettes\n• 8 HDRI environments\n• UI flags"]
        Y["usePorscheSoundSettings\n• 13 Audio channels\n• Playback state flags\n• Preloaded Audio nodes"]
        Z["useSceneSettings\n• Camera control flags\n• Animation played flags\n• CameraControls mode"]
    end

    N --> X
    N --> Y
    T --> X
    T --> Y
    T --> Z
    Q --> X
    K --> X

    classDef entry fill:#1a1a2e,color:#fff,stroke:#7c3aed
    classDef store fill:#0f3460,color:#fff,stroke:#0ea5e9
Loading

🎬 Rendering Pipeline

flowchart LR
    A["GLTF Model\n(gltfjsx component)"] --> B["MeshStandardMaterial\n(PBR)"]
    B --> C["Color Uniform\n(Zustand currentPorscheColor)"]
    B --> D["Metalness Uniform\n(per-car Zustand value)"]
    B --> E["Roughness Uniform\n(per-car Zustand value)"]

    F["Environment.hdr\n(Polyhaven CDN stream)"] --> G["IBL\n(Image-Based Lighting)"]
    G --> B

    H["AccumulativeShadows\n(SoftShadow baking)"] --> I["Ground Contact Shadow\n(Shadow Plane)"]

    B --> J["WebGL Render Pass"]
    I --> J
    G --> J

    J --> K["EffectComposer"]
    K --> L["BloomEffect\n(intensity: 0.24\nkernelSize: 1\nluminanceThreshold: 0.0\nmipmapBlur: true\nresolution: 64×64)"]
    L --> M["VignetteEffect\n(offset: 0.5\ndarkness: 0.5\nblend: NORMAL)"]
    M --> N["🖥️ Canvas Output"]
Loading

⚡ Scene Initialization Sequence

This is the most critical orchestration in the entire application. The configurator scene boots in 4 strict sequential phases to prevent race conditions between asset loading, shadow baking, and camera choreography:

sequenceDiagram
    participant U as User
    participant A as App
    participant DC as DynamicCarChanging
    participant ACC as AccumulativeShadows
    participant ICL as InitialConfiguratorLogics
    participant UI as InitLogicNavConfig
    participant SND as AudioEngine

    U->>A: Navigate to /configurator
    A->>DC: Mount DynamicCarChanging (Suspense)
    Note over DC: Lazy-import GLTF component for currentCar
    DC-->>A: setRenderedCar(true) ✅ Phase 1 Complete

    A->>ACC: Mount MemoLighterAccumulativeShadows
    Note over ACC: Progressive shadow baking begins
    ACC-->>A: setRenderedAccumulativeShadow(true) ✅ Phase 2 Complete

    A->>ICL: Mount InitialConfiguratorLogics (gated on renderedAccumulativeShadow)
    ICL->>ICL: Check playedInitialConfiguratorAnimation
    alt First Visit
        ICL->>ICL: Run 5-step cinematic camera timeline (GSAP)
        Note over ICL: Step 1: Rear approach<br/>Step 2: Side sweep<br/>Step 3: Rear pan<br/>Step 4: Detail zoom-in<br/>Step 5: Final hero position
        ICL->>SND: playLogoSound() @ t+500ms
        ICL->>SND: playInitialSound() + playMusic() @ t+1500ms
    else Return Visit
        ICL->>ICL: setLookAt() to saved hero position instantly
    end
    ICL-->>A: setStartedScene(true) ✅ Phase 3 Complete

    A->>UI: Mount InitLogicNavConfig (gated on startedScene)
    UI->>UI: GSAP entrance animations for 2D UI elements
    Note over UI: Nav bar, menu icons, overlays fade in
    UI-->>U: ✅ Phase 4 Complete — Scene Interactive
Loading

🗄️ State Management Architecture

Three specialized Zustand stores isolate concerns with zero cross-store coupling:

graph LR
    subgraph STORE1 ["usePorscheConfiguratorSettings (672 lines)"]
        direction TB
        S1A["Scene Flags\n• renderedCar\n• renderedAccumulativeShadow\n• startedScene\n• beenToHomepage"]
        S1B["Car Selection\n• currentCar (0-6)\n• porscheModelList[7]\n• porscheListConfigs[7]"]
        S1C["PBR Material\n• metalness per model\n• roughness per model\n• currentPorscheColor\n• porscheColorLists[16]"]
        S1D["Camera Presets\n• exterior[8] keyframes per car\n• interior[5] keyframes per car\n• interiorOrNot\n• exteriorInspectMode\n• interiorInspectMode"]
        S1E["Environment\n• environments[8]\n• currentEnvironmentIndex\n• HDR path + intensity\n• ground params (interior/exterior)"]
        S1F["UI State\n• leftSideMenu\n• drawerIframe\n• currentDrawer\n• sprayStatus\n• turnOnHeadLight"]
    end

    subgraph STORE2 ["usePorscheSoundSettings (213 lines)"]
        direction TB
        S2A["Preloaded Tracks\n• 13 HTMLAudioElement instances\n• All preloaded on module eval"]
        S2B["Playback State Flags\n• playedInitialSound\n• playedDoorCloseSound\n• playedInteriorSound\n• playedEnvironmentSound\n• playedMusic"]
        S2C["Play/Stop Actions\n• Door open/close\n• Initial engine\n• Interior ambience\n• Logo sting\n• Environment\n• Background music\n• UI SFX (click/hover/back)\n• Paint SFX (shake/change/finish)"]
    end

    subgraph STORE3 ["useSceneSettings (small)"]
        direction TB
        S3A["CameraControls Ref State\n• configuratorCameraControlsStore\n• toggleConfiguratorCameraControls()"]
        S3B["Animation State\n• playedInitialConfiguratorAnimation\n• playedInitialHomeAnimation\n• togglePlayedInitialConfiguratorAnimation()"]
        S3C["Mode Flags\n• configuratorCameraControlsMode\n• toggleConfiguratorCameraControlsMode()"]
    end
Loading

🎥 Camera Control System

The camera system is one of the most intricate parts of PorscheLab. It uses @react-three/drei's CameraControls with handcrafted 6-DOF keyframe arrays stored per model.

flowchart TD
    A["User Action\n(UI Button Click)"] --> B{Check Mode}

    B --> C["Exterior Inspect Mode\nexteriorInspectMode: 0-7"]
    B --> D["Interior Mode\ninteriorOrNot: true"]
    B --> E["Free Orbit\n(CameraControls enabled)"]

    C --> F["Read from Store:\nporscheListConfigs[currentCar].exterior[exteriorInspectMode]\n= [posX, posY, posZ, targetX, targetY, targetZ, transition]"]
    D --> G["Read from Store:\nporscheListConfigs[currentCar].interior[interiorInspectMode]\n= [posX, posY, posZ, targetX, targetY, targetZ, transition]\n\nConstraints:\n• smoothTime: 0.3 (fast)\n• maxPolarAngle: PI/1.5\n• minDistance: 0.05\n• maxDistance: 0.1"]
    E --> H["Mouse: Rotate / Dolly\nTouch: RotateTouch / DollyTouch\n\nConstraints:\n• smoothTime: 1.0 (slow)\n• maxPolarAngle: PI/2 (no flip)\n• minDistance: 2.8\n• maxDistance: 5"]

    F --> I["cameraControlsRef.current?.setLookAt(..., animate)"]
    G --> I
    H --> I

    I --> J["Three.js CameraControls\nInterpolates per-frame"]
    J --> K["🖥️ Rendered View"]

    subgraph INTERIOR_SFX ["Side Effects"]
        L["playDoorCloseSound()"]
        M["playInteriorSound()"]
        N["playDoorOpenSound() on exit"]
    end

    D --> L
    D --> M
    B --> N
Loading

🔊 Audio Engine Architecture

graph TD
    INIT["Module Evaluation\n(usePorscheSoundSettings.tsx)"]

    INIT --> T1["soundDoorClose\nporsche_door_close.mp3\nvol: 0.2"]
    INIT --> T2["soundDoorOpen\nporsche_door_open.mp3\nvol: 0.2"]
    INIT --> T3["soundPorscheConfigStart\nporsche_configurator_start.mp3\nvol: 0.2"]
    INIT --> T4["soundPorscheConfigInterior\nporsche_configurator_interior.mp3\nvol: 0.2"]
    INIT --> T5["soundPorscheLogo\nporsche_logo_sound.mp3\nvol: 0.2"]
    INIT --> T6["soundEnvironment\nporsche_environment.mp3\nvol: 0.2"]
    INIT --> T7["soundMusic\nwaves-to-particles.mp3\nvol: 0.2 | loop: true"]
    INIT --> T8["clickButton\nbutton-click.mp3\nvol: 0.2"]
    INIT --> T9["backButton\nbutton-back.mp3\nvol: 0.2"]
    INIT --> T10["hoverButton\nbutton-hover.mp3\nvol: 0.2"]
    INIT --> T11["colorInputChange\ncolor-input-change.mp3\nvol: 0.05"]
    INIT --> T12["colorInputChangeFinished\ncolor-input-change-finished.mp3\nvol: 0.05"]
    INIT --> T13["shakingSpray\nshake-spray.mp3\nvol: 0.2"]

    subgraph GATE ["State-Gated Playback (Zustand flags)"]
        G1["playedInitialSound → play once on first configurator mount"]
        G2["playedDoorCloseSound → play once per interior entry session"]
        G3["playedInteriorSound → play once per interior visit"]
        G4["playedEnvironmentSound → play once per environment panel open"]
    end

    T3 --> G1
    T1 --> G2
    T4 --> G3
    T6 --> G4
Loading

🔧 3D Model Pipeline

Each Porsche model goes through a specialized asset pipeline before appearing in the browser:

flowchart LR
    A["Original .GLB\n(Blender / Source)"] --> B["gltfjsx CLI\n(@react-three/gltfjsx)"]
    B --> C["Auto-generated TSX Component\n(typed nodes, materials, animations)"]
    C --> D["Manual PBR Binding\n• Inject Zustand metalness\n• Inject Zustand roughness\n• Inject Zustand color\n• Wire headlight emission toggle\n• Calibrate per-mesh material params"]
    D --> E["Lazy Import Wrapper\n(DynamicCarChanging.tsx)"]
    E --> F["Code Split Chunk\n(Vite build output)"]
    F --> G["Suspense boundary\n(null fallback, invisible load)"]
    G --> H["🖥️ Rendered in WebGL Scene"]

    subgraph MODELS ["7 Models — Individual Chunk Sizes"]
        M1["PorscheSpyder.tsx\n~196KB source"]
        M2["Porsche911GT3RS.tsx\n~176KB source"]
        M3["PorscheTaycan.tsx\n~78KB source"]
        M4["PorschePanamera.tsx\n~96KB source"]
        M5["Porsche911TurboS.tsx\n~44KB source"]
        M6["PorscheCayenne.tsx\n~16KB source"]
        M7["PorscheCayman.tsx\n~14KB source"]
    end
Loading

📜 Homepage Scroll Animation System

The homepage features a multi-chapter GSAP ScrollTrigger narrative with over 30 individual animation directives, pinned sections, and reactive text swapping:

sequenceDiagram
    participant S as ScrollPosition
    participant G as GSAP ScrollTrigger
    participant D as DOM

    S->>G: homepageHero bottom hits viewport bottom
    G->>D: Fade + blur homepageHero (opacity 0, blur 5px)
    G->>D: Transition background: black → white

    S->>G: aboutContainer enters viewport
    G->>D: aboutText1 parallax (y: -700 → 250)
    G->>D: aboutImage1 reveal (opacity 0 → 1, y: -500 → 250)
    G->>D: innerAboutImage1 expand (width: 90% → 100%)

    S->>G: aboutContainer2 enters
    G->>D: aboutContainer2 fade up
    G->>D: aboutText2 slide up reveal
    G->>D: aboutVideo parallax y shift

    S->>G: about__video center hits bottom
    G->>D: Expand aboutVideo to 100vw × 100vh
    G->>D: Background: white → black

    S->>G: historySection__headLine enters
    G->>D: SplitText word-by-word stagger reveal
    G->>D: historySection__historyHR width: 0 → 100%
    G->>D: about__video fade out

    Note over G,D: PIN historySection__explaination for 4000px of scroll

    loop For each of 6 history timeline entries
        S->>G: historyImage[n] enters viewport (top 70%)
        G->>D: Image zoom (width → 60%) + blur out
        G->>D: Swap title text with GSAP TextPlugin
        G->>D: Swap description text with GSAP TextPlugin
    end

    G->>D: historySection__historyContainer fade out

    S->>G: historyPresent__container enters
    G->>D: presentEraImg fade in
    G->>D: presentEraLogo brightness invert
    Note over G,D: PIN historyPresent__container for 3000px

    S->>G: chooseCar__container enters
    G->>D: historyPresent fade out + blur(5px)
    G->>D: chooseCar__openingMessage color reveal
    G->>D: chooseCar__carList opacity reveal
Loading

🖥️ Configurator UI Layer

graph TD
    NAV["NavigateBarConfigurator.tsx"]

    NAV --> TOP["Top Navigation Bar"]
    TOP --> TL["Hamburger → Model Detail\n(toggleLeftSideMenu)"]
    TOP --> TC["Porsche Logo + Model Name Logo\n(per-car dynamic icon)"]
    TOP --> TR["Right Icon Menu\n(6 icons)"]

    TR --> I1["🎨 Spray\n→ Toggle color picker panel"]
    TR --> I2["🚗 Front Car\n→ Cycle exterior keyframes"]
    TR --> I3["🏎️ Steering Wheel\n→ Enter interior mode\n+ play door close SFX"]
    TR --> I4["🌄 Environment\n→ Open HDRI selector\n+ play environment SFX"]
    TR --> I5["🔄 Change Car\n→ Open car switcher panel"]
    TR --> I6["💡 Headlight\n→ toggleHeadLight()"]

    NAV --> BOTTOM["Bottom Action Bar"]
    BOTTOM --> BC["Color Picker\n• input[type=color] → setCurrentPorscheColor\n• 16 preset swatches\n• GSAP smooth color transition\n• Spray shake SFX"]
    BOTTOM --> BS["Surface Controls\n• Roughness slider (0-1)\n• Metalness slider (0-1)\n• Per-model state in Zustand"]
    BOTTOM --> BB["Back Button\n→ Stop all audio\n→ navigate('/')"]

    NAV --> LEFT["Left Slide Panel\n(PorscheConfiguratorLeftMenu)\n• Model Detail accordion"]
    NAV --> RIGHT["Right Drawer Panel\n(PorscheConfiguratorRightMenuPages)\n• Dynamic content per icon\n• GSAP slide-in transition"]

    NAV --> OVL["navigateConfig__overlay\n(GSAP backdrop-filter blur\nduring model loading)"]
Loading

🌅 HDR Environment System

graph LR
    subgraph CONFIG ["Environment Config (per entry)"]
        N["name: string"]
        IMG["image: /images/environments/...webp\n(thumbnail)"]
        PATH["environmentPath: polyhaven CDN URL\n(resolution: 2k|4k based on viewport width)"]
        EI["environmentIntensity: number"]
        EG["envGround: height/radius/scale\n(exterior view)"]
        EGI["envGroundInterior: height/radius/scale\n(interior view)"]
    end

    subgraph RES ["Resolution Selection (on module load)"]
        W["window.innerWidth < 1100"] --> R2K["resolution = '2k'\n(performance)"]
        W --> R4K["resolution = '4k'\n(quality)"]
    end

    subgraph ENVLIST ["8 Environments Available"]
        E1["Forest Path\n(tief_etz)"]
        E2["Victoria Sunset"]
        E3["Overcast Soil"]
        E4["Abandoned Lot\n(lot_02)"]
        E5["Rural Winter Roadside"]
        E6["Zawiszy Czarnego"]
        E7["Small Rural Road"]
        E8["Zwartkops Start Sunset"]
    end

    PATH --> DREI["@react-three/drei Environment\nfiles={environmentPath}\nenvironmentIntensity={...}\nground={interiorOrNot ? envGroundInterior : envGround}"]
    DREI --> IBL["IBL Applied to all PBR materials in scene"]
Loading

🚀 Deployment Pipeline

flowchart LR
    A["Developer\ngit push"] --> B["Netlify CI"]
    B --> C["Install Node 24"]
    C --> D["cd client/\nnpm install"]
    D --> E["tsc -b (TypeScript check)"]
    E --> F["vite build\n(ESM + code splitting)"]
    F --> G["dist/ output\n• Per-car lazy chunks\n• Asset hashing\n• Compressed bundles"]
    G --> H["Netlify CDN\nEdge distribution"]
    H --> I["SPA Redirect rule\n/* → /index.html : 200\n(client-side routing)"]
    I --> J["🌐 Live Site"]
Loading

📁 Project Structure

PorscheLab/
├── netlify.toml                    # Netlify build config + SPA redirect
└── client/
    ├── package.json                # Dependencies manifest
    ├── vite.config.ts              # Vite build config
    ├── tsconfig.json               # TypeScript project references
    ├── index.html                  # Entry HTML + meta tags
    └── src/
        ├── main.tsx                # App root: Router + lazy page imports
        ├── index.css               # Global reset + CSS custom properties
        ├── pages/
        │   ├── Homepage.tsx                      # Homepage page + loading screen
        │   ├── PorscheConfigurator.tsx           # Main 3D scene orchestrator
        │   └── ProtectedPorscheConfigurator.tsx  # Route guard wrapper
        ├── Components/
        │   ├── Logics/
        │   │   ├── InitLogic.tsx                 # Homepage GSAP ScrollTrigger orchestrator
        │   │   ├── InitLogicNavConfig.tsx        # Configurator 2D UI entrance animations
        │   │   ├── InitialConfiguratorLogics.tsx # 3D camera cinematic sequence
        │   │   └── HeroContentFrameUpdater.tsx   # Hero frame sync utility
        │   ├── SceneObjects/
        │   │   ├── DynamicCarChanging.tsx         # Lazy model switcher
        │   │   ├── Porsche911GT3RS.tsx             # gltfjsx PBR component (176KB)
        │   │   ├── PorscheSpyder.tsx               # gltfjsx PBR component (196KB)
        │   │   ├── PorscheTaycan.tsx               # gltfjsx PBR component (78KB)
        │   │   ├── PorschePanamera.tsx             # gltfjsx PBR component (96KB)
        │   │   ├── Porsche911TurboS.tsx            # gltfjsx PBR component (44KB)
        │   │   ├── PorscheCayenne.tsx              # gltfjsx PBR component (16KB)
        │   │   ├── PorscheCayman.tsx               # gltfjsx PBR component (14KB)
        │   │   └── Light/
        │   │       └── MemoLighterAccumulativeShadows.tsx
        │   ├── Post-processing/
        │   │   └── EffectComposerHero.tsx          # Bloom + Vignette composer
        │   └── UI/
        │       ├── NavigateBarConfigurator.tsx     # Full configurator UI overlay (497 lines)
        │       ├── NavigateBar.tsx                 # Homepage navigation
        │       ├── HomepageMain.tsx                # Homepage layout root
        │       ├── HomepageContent.tsx             # Hero + sections container
        │       ├── HomepageHistorySection.tsx      # 6-chapter scroll history
        │       ├── HomepagePresentSection.tsx      # Present era pinned section
        │       ├── HomepageLeftMenu.tsx            # Homepage sidebar nav
        │       ├── HomepageFooter.tsx              # Footer component
        │       ├── HomepageVideoClicking.tsx       # Video popup trigger
        │       ├── VideoPopupComponent.tsx         # Modal video player
        │       ├── TransitionToConfigurator.tsx    # Page transition handler
        │       ├── PorscheConfiguratorLeftMenu.tsx # Model detail left panel
        │       ├── PorscheConfiguratorRightMenuPages.tsx # Dynamic right panel
        │       ├── LoadingScreen/
        │       │   └── LoadingHomeScreen.tsx       # WebGL asset load overlay
        │       └── Skeletons/
        ├── stores/
        │   ├── usePorscheConfiguratorSettings.tsx # Primary state store (672 lines)
        │   ├── usePorscheSoundSettings.tsx         # 13-channel audio engine (213 lines)
        │   ├── useSceneSettings.tsx                # Camera + animation flags
        │   └── useCameraControls.tsx               # CameraControls ref store
        ├── styles/
        │   ├── canvas.css
        │   ├── nav.css
        │   ├── loadingScreen.css
        │   ├── fonts/
        │   └── components/ + pages/
        ├── types/
        │   ├── porscheConfigType.ts
        │   └── environemtnConfigType.ts
        ├── utils/
        │   └── gsapColorSmoothChange.ts    # GSAP-driven PBR color transition util
        └── statics/
            └── (static data / constants)

🚀 Getting Started

Prerequisites

  • Node.js ≥ 18 (24 recommended, matches Netlify)
  • npm ≥ 9

Installation

# Clone repository
git clone https://github.com/yourusername/PorscheLab.git
cd PorscheLab/client

# Install dependencies
npm install

Development Server

npm run dev
# → http://localhost:5173

Production Build

npm run build
# Output: client/dist/

Type Check

tsc -b --noEmit

Lint

npm run lint

⚡ Performance Considerations

Strategy Implementation
Lazy model loading Each of 7 car models is a separate Vite code-split chunk, loaded only when selected
Suspense boundaries null fallback prevents layout shifts during model swaps
Resolution-adaptive HDR 2K HDRIs on viewports < 1100px, 4K on desktop
Bloom at 64×64 Post-processing resolve at 64px to minimize GPU memory bandwidth
Memoized shadows MemoLighterAccumulativeShadows wrapped in React.memo to prevent re-baking
Audio preload All 13 audio tracks preloaded on module evaluation to avoid latency on first trigger
State-gated sounds Zustand boolean flags prevent duplicate audio on React StrictMode double-renders
frameloop: always Continuous rendering loop for smooth camera interpolation (not demand-based)
CameraControls constraints minDistance/maxDistance/maxPolarAngle prevent degenerate camera states
GSAP overwrite: auto Prevents animation stacking on rapid UI interactions

Built with passion for precision engineering and the art of driving.

"In the beginning I looked around and, not finding the automobile of my dreams, decided to build it myself."Ferry Porsche


🔒 Private Project

This is a closed, private project. The source code is not publicly available and is not open for redistribution, forking, or reuse.

All rights reserved © 2025 — This repository is for portfolio and showcase purposes only.


Crafted by R3Vision

R3Vision — A creative development studio focused on pushing the boundaries of real-time 3D, interactive web experiences, and immersive digital products.

From concept to pixel-perfect execution — built with obsession for craft.

About

Real-time 3D Porsche configurator website — WebGL · React Three Fiber · GSAP · 60-120 FPS · Mobile 100% | Featured by Three.js

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors