Tesla UHD Electric Vehicle Landing Page
A premium dark-themed electric vehicle landing page inspired by Tesla — featuring animated gradient mesh backgrounds, glassmorphism model cards, CSS-only vehicle silhouettes, scroll-pinned technology reveals, animated stat counters, and a dashboard mockup with parallax tilt.
Open in Lab
MCP
gsap scrolltrigger lenis css vanilla-js canvas
Targets: JS HTML
Code
/* ═══════════════════════════════════════════════════════════════════════
Tesla UHD Electric Vehicle Landing Page — Styles
═══════════════════════════════════════════════════════════════════════ */
:root {
--ts-black: #000000;
--ts-dark: #0a0a0a;
--ts-surface: #1a1a1a;
--ts-border: rgba(255, 255, 255, 0.08);
--ts-red: #e82127;
--ts-red-glow: rgba(232, 33, 39, 0.25);
--ts-red-subtle: rgba(232, 33, 39, 0.08);
--ts-blue: #3e68ff;
--ts-blue-glow: rgba(62, 104, 255, 0.25);
--ts-text: #ffffff;
--ts-muted: #999999;
--ts-dim: #555555;
--glass-bg: rgba(255, 255, 255, 0.04);
--glass-border: rgba(255, 255, 255, 0.08);
--glass-hover: rgba(255, 255, 255, 0.07);
--radius: 16px;
--radius-lg: 24px;
--font: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font);
background: var(--ts-black);
color: var(--ts-text);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
/* ── Canvas background ── */
#mesh-bg {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
}
main {
position: relative;
z-index: 1;
}
/* ── Shared ── */
section {
position: relative;
padding: 120px 1.5rem;
}
.section-container {
max-width: 1100px;
margin: 0 auto;
}
.section-header {
margin-bottom: 3.5rem;
}
.section-title {
font-size: clamp(2.5rem, 7vw, 4.5rem);
font-weight: 700;
line-height: 1.05;
letter-spacing: -0.04em;
margin-bottom: 1rem;
}
.text-muted {
color: var(--ts-muted);
font-size: 1.05rem;
line-height: 1.6;
}
.text-sm {
font-size: 0.875rem;
}
.tag {
display: inline-block;
padding: 6px 16px;
background: var(--ts-red);
color: #fff;
border-radius: 100px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
margin-bottom: 1.25rem;
}
.reveal {
opacity: 0;
transform: translateY(30px);
}
/* ── Buttons ── */
.btn-primary {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 40px;
background: var(--ts-red);
color: #fff;
border: none;
border-radius: 100px;
font-size: 0.95rem;
font-weight: 600;
letter-spacing: 0.02em;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.btn-primary:hover {
transform: scale(1.04);
box-shadow: 0 0 40px var(--ts-red-glow);
}
.btn-glow {
box-shadow: 0 0 30px var(--ts-red-glow), 0 0 60px rgba(232, 33, 39, 0.1);
}
.btn-outline {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 40px;
background: transparent;
color: var(--ts-text);
border: 1px solid var(--glass-border);
border-radius: 100px;
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
transition: border-color 0.3s ease, background 0.3s ease;
}
.btn-outline:hover {
border-color: rgba(255, 255, 255, 0.2);
background: var(--glass-bg);
}
/* ── Glass card ── */
.glass-card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
/* ═══════════════════════════════════════════════════════════════════════
HERO
═══════════════════════════════════════════════════════════════════════ */
.hero {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 1.5rem 60px;
gap: 2rem;
}
.hero-content {
position: relative;
z-index: 2;
}
.hero-eyebrow {
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.35em;
color: var(--ts-red);
margin-bottom: 1.5rem;
opacity: 0;
}
.hero-title {
font-size: clamp(4rem, 14vw, 10rem);
font-weight: 300;
letter-spacing: -0.05em;
line-height: 0.9;
background: linear-gradient(180deg, #fff 30%, #555 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
opacity: 0;
}
.hero-subtitle {
font-size: clamp(1rem, 2.5vw, 1.3rem);
color: var(--ts-muted);
font-weight: 400;
margin-top: 1.5rem;
letter-spacing: 0.01em;
opacity: 0;
}
.hero-actions {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-top: 2.5rem;
opacity: 0;
}
/* ── Scroll indicator ── */
.scroll-indicator {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.75rem;
opacity: 0;
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
}
.scroll-indicator span {
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.2em;
color: var(--ts-dim);
font-weight: 500;
}
.scroll-line {
width: 1px;
height: 40px;
background: linear-gradient(180deg, var(--ts-red), transparent);
animation: scrollPulse 2s ease-in-out infinite;
}
@keyframes scrollPulse {
0%,
100% {
opacity: 0.3;
transform: scaleY(0.6);
}
50% {
opacity: 1;
transform: scaleY(1);
}
}
/* ═══════════════════════════════════════════════════════════════════════
MODEL LINEUP
═══════════════════════════════════════════════════════════════════════ */
.models-section {
padding: 140px 1.5rem;
}
.models-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
}
.model-card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius);
padding: 2rem 1.5rem 1.5rem;
text-align: center;
position: relative;
transition: transform 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
opacity: 0;
transform: translateY(30px) scale(0.96);
}
.model-card:hover {
transform: translateY(-4px) scale(1.02);
border-color: rgba(232, 33, 39, 0.2);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4), 0 0 40px var(--ts-red-subtle);
}
.model-card-featured {
border-color: rgba(232, 33, 39, 0.15);
background: linear-gradient(135deg, rgba(232, 33, 39, 0.06), var(--glass-bg));
}
.model-silhouette {
height: 80px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.25rem;
color: var(--ts-text);
}
.model-silhouette svg {
width: 100%;
max-width: 180px;
height: auto;
opacity: 0.7;
transition: opacity 0.3s ease;
}
.model-card:hover .model-silhouette svg {
opacity: 1;
}
.model-name {
font-size: 1.1rem;
font-weight: 600;
letter-spacing: -0.02em;
margin-bottom: 0.25rem;
}
.model-spec {
font-size: 0.8rem;
color: var(--ts-muted);
margin-bottom: 1rem;
}
.model-meta {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 0.75rem;
border-top: 1px solid var(--glass-border);
}
.model-stat {
font-size: 0.7rem;
color: var(--ts-red);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.model-price {
font-size: 0.75rem;
color: var(--ts-dim);
font-weight: 500;
}
.new-badge {
position: absolute;
top: 12px;
right: 12px;
padding: 3px 10px;
background: var(--ts-red);
color: #fff;
border-radius: 100px;
font-size: 9px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
}
/* ═══════════════════════════════════════════════════════════════════════
TECHNOLOGY (pinned scroll)
═══════════════════════════════════════════════════════════════════════ */
.how-track {
height: 300vh;
padding: 0;
}
.how-sticky {
position: sticky;
top: 0;
height: 100vh;
display: flex;
align-items: center;
padding: 0 1.5rem;
max-width: 1100px;
margin: 0 auto;
gap: 4rem;
}
.how-content {
flex: 1;
position: relative;
padding-left: 3rem;
}
.step-dots {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
gap: 12px;
}
.step-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--ts-dim);
transition: background 0.4s ease, box-shadow 0.4s ease, transform 0.4s ease;
cursor: pointer;
}
.step-dot.active {
background: var(--ts-red);
box-shadow: 0 0 12px var(--ts-red-glow);
transform: scale(1.3);
}
.step-card {
display: none;
}
.step-card.active {
display: block;
animation: fadeUp 0.5s ease forwards;
}
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.step-heading {
font-size: clamp(2rem, 5vw, 3.2rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
margin-bottom: 1rem;
}
.step-desc {
color: var(--ts-muted);
font-size: 1rem;
line-height: 1.7;
max-width: 420px;
}
.how-visuals {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.how-visual {
display: none;
width: 100%;
justify-content: center;
}
.how-visual.active {
display: flex;
animation: fadeUp 0.5s ease forwards;
}
.tech-visual-card {
width: 240px;
height: 280px;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
gap: 1.5rem;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
}
.tech-icon-svg {
width: 140px;
height: 140px;
color: var(--ts-text);
}
.tech-visual-label {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.15em;
color: var(--ts-dim);
font-weight: 500;
text-align: center;
}
/* Pulse ring animation */
.pulse-ring {
animation: pulseRing 3s ease-in-out infinite;
}
@keyframes pulseRing {
0%,
100% {
opacity: 0.1;
}
50% {
opacity: 0.3;
}
}
/* ═══════════════════════════════════════════════════════════════════════
STATS
═══════════════════════════════════════════════════════════════════════ */
.stats-section {
padding: 140px 1.5rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
text-align: center;
}
.stat-item {
padding: 2.5rem 1.5rem;
}
.stat-number {
font-size: clamp(3rem, 8vw, 5rem);
font-weight: 700;
letter-spacing: -0.04em;
line-height: 1;
background: linear-gradient(135deg, #fff 40%, var(--ts-red) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 0.5rem;
}
.stat-label {
font-size: 0.85rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--ts-text);
margin-bottom: 0.5rem;
}
.stat-desc {
font-size: 0.85rem;
color: var(--ts-dim);
line-height: 1.5;
}
/* ═══════════════════════════════════════════════════════════════════════
SAFETY
═══════════════════════════════════════════════════════════════════════ */
.safety-section {
padding: 100px 1.5rem;
}
.safety-card {
padding: 3.5rem;
}
.safety-header {
text-align: center;
margin-bottom: 2.5rem;
}
.safety-icon {
width: 56px;
height: 56px;
margin: 0 auto 1.5rem;
color: var(--ts-text);
}
.safety-icon svg {
width: 100%;
height: 100%;
}
.safety-stars {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
margin-bottom: 3rem;
}
.safety-features {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.safety-feature {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1.25rem;
border-radius: var(--radius);
border: 1px solid transparent;
transition: background 0.3s ease, border-color 0.3s ease;
}
.safety-feature:hover {
background: var(--glass-bg);
border-color: var(--glass-border);
}
.sf-icon {
width: 40px;
height: 40px;
min-width: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: var(--ts-red-subtle);
color: var(--ts-red);
}
.sf-title {
font-size: 0.95rem;
font-weight: 600;
margin-bottom: 0.25rem;
}
/* ═══════════════════════════════════════════════════════════════════════
DASHBOARD SHOWCASE
═══════════════════════════════════════════════════════════════════════ */
.dashboard-section {
padding: 140px 1.5rem;
}
.dash-grid {
display: grid;
grid-template-columns: 1fr 1.4fr;
align-items: center;
gap: 4rem;
}
.dash-device {
position: relative;
perspective: 800px;
}
.dashboard-screen {
width: 100%;
max-width: 480px;
aspect-ratio: 16 / 10;
background: linear-gradient(145deg, rgba(20, 20, 20, 0.95), rgba(10, 10, 10, 0.98));
border: 1px solid var(--glass-border);
border-radius: 16px;
overflow: hidden;
display: flex;
flex-direction: column;
padding: 10px 14px;
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.04);
transform-style: preserve-3d;
transition: transform 0.1s ease;
}
.device-glow {
position: absolute;
inset: -20%;
background: radial-gradient(ellipse at center, var(--ts-red-glow), transparent 70%);
opacity: 0.15;
pointer-events: none;
z-index: -1;
}
/* Dashboard top bar */
.dash-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 6px 8px;
font-size: 9px;
color: var(--ts-muted);
font-weight: 500;
}
.dash-time {
font-variant-numeric: tabular-nums;
}
.dash-temp-ambient {
color: var(--ts-dim);
}
.dash-signal-bars {
display: flex;
gap: 1.5px;
align-items: flex-end;
}
.dash-signal-bars span {
display: block;
width: 3px;
background: var(--ts-muted);
border-radius: 1px;
}
.dash-signal-bars span:nth-child(1) {
height: 4px;
}
.dash-signal-bars span:nth-child(2) {
height: 6px;
}
.dash-signal-bars span:nth-child(3) {
height: 8px;
}
.dash-signal-bars span:nth-child(4) {
height: 10px;
opacity: 0.3;
}
/* Dashboard main layout */
.dash-main {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
}
/* Speedometer */
.dash-speedo {
flex: 0 0 90px;
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
}
.speedo-arc {
width: 80px;
height: 55px;
position: relative;
}
.speedo-svg {
width: 100%;
height: 100%;
}
.speedo-value {
font-size: 26px;
font-weight: 300;
letter-spacing: -0.03em;
line-height: 1;
margin-top: -6px;
}
.speedo-unit {
font-size: 8px;
color: var(--ts-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
}
.speedo-gear {
font-size: 10px;
font-weight: 600;
color: var(--ts-red);
margin-top: 4px;
}
/* Center car view */
.dash-center {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
min-height: 140px;
}
.dash-car-topview {
width: 60px;
color: var(--ts-text);
}
.dash-car-topview svg {
width: 100%;
height: auto;
}
/* Route visualization */
.dash-route {
position: absolute;
top: 10%;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 80%;
display: flex;
flex-direction: column;
align-items: center;
}
.route-line {
width: 1px;
flex: 1;
background: linear-gradient(180deg, transparent, var(--ts-blue), transparent);
opacity: 0.2;
}
.route-dot {
width: 4px;
height: 4px;
border-radius: 50%;
}
.route-dot-start {
background: var(--ts-blue);
box-shadow: 0 0 6px var(--ts-blue-glow);
}
.route-dot-end {
background: var(--ts-red);
box-shadow: 0 0 6px var(--ts-red-glow);
}
/* Right info panel */
.dash-info {
flex: 0 0 90px;
display: flex;
flex-direction: column;
gap: 16px;
}
/* Battery */
.dash-battery {
display: flex;
flex-direction: column;
gap: 4px;
}
.battery-label {
font-size: 7px;
color: var(--ts-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 500;
}
.battery-bar {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.06);
border-radius: 3px;
overflow: hidden;
}
.battery-fill {
width: 78%;
height: 100%;
background: linear-gradient(90deg, var(--ts-blue), #4ade80);
border-radius: 3px;
}
.battery-pct {
font-size: 14px;
font-weight: 600;
letter-spacing: -0.02em;
}
.battery-range {
font-size: 8px;
color: var(--ts-dim);
}
/* Climate */
.dash-climate {
display: flex;
flex-direction: column;
gap: 4px;
}
.climate-label {
font-size: 7px;
color: var(--ts-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 500;
}
.climate-temps {
display: flex;
align-items: center;
gap: 6px;
}
.climate-driver,
.climate-passenger {
display: flex;
align-items: baseline;
gap: 2px;
}
.climate-val {
font-size: 14px;
font-weight: 500;
}
.climate-side {
font-size: 7px;
color: var(--ts-dim);
}
.climate-divider {
width: 1px;
height: 16px;
background: var(--glass-border);
}
/* Dashboard bottom nav */
.dash-bottom {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
padding: 8px 0 4px;
border-top: 1px solid rgba(255, 255, 255, 0.04);
}
.dash-nav-btn {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
color: var(--ts-dim);
transition: color 0.3s ease, background 0.3s ease;
}
.dash-nav-btn.active {
color: var(--ts-red);
background: var(--ts-red-subtle);
}
/* ═══════════════════════════════════════════════════════════════════════
FINAL CTA
═══════════════════════════════════════════════════════════════════════ */
.cta-section {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
overflow: hidden;
padding: 120px 1.5rem;
}
.cta-title {
font-size: clamp(3rem, 10vw, 6rem);
font-weight: 300;
letter-spacing: -0.04em;
}
.cta-subtitle {
max-width: 420px;
margin-bottom: 2.5rem;
}
.cta-buttons {
display: flex;
gap: 1rem;
align-items: center;
}
/* Rings */
.cta-rings {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
.ring {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(232, 33, 39, 0.12);
opacity: 0;
}
.ring-1 {
width: 300px;
height: 300px;
}
.ring-2 {
width: 500px;
height: 500px;
}
.ring-3 {
width: 700px;
height: 700px;
}
/* CTA Orbs */
.cta-orbs {
position: absolute;
inset: 0;
pointer-events: none;
}
.cta-orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
}
.cta-orb-1 {
width: 300px;
height: 300px;
background: var(--ts-red-glow);
top: 20%;
left: 15%;
opacity: 0.3;
}
.cta-orb-2 {
width: 250px;
height: 250px;
background: var(--ts-blue-glow);
bottom: 20%;
right: 15%;
opacity: 0.2;
}
/* ═══════════════════════════════════════════════════════════════════════
RESPONSIVE
═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
.models-grid {
grid-template-columns: repeat(2, 1fr);
}
.how-sticky {
flex-direction: column;
gap: 2rem;
padding: 2rem 1.5rem;
text-align: center;
}
.how-content {
padding-left: 0;
}
.step-dots {
position: relative;
flex-direction: row;
transform: none;
justify-content: center;
top: auto;
left: auto;
margin-bottom: 1rem;
}
.step-desc {
max-width: none;
}
.dash-grid {
grid-template-columns: 1fr;
gap: 3rem;
text-align: center;
}
.dash-device {
display: flex;
justify-content: center;
}
.stats-grid {
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
}
@media (max-width: 768px) {
section {
padding: 80px 1rem;
}
.models-grid {
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.safety-card {
padding: 2rem 1.5rem;
}
.hero-actions {
flex-direction: column;
gap: 0.75rem;
}
.cta-buttons {
flex-direction: column;
gap: 0.75rem;
}
.dashboard-screen {
max-width: 380px;
}
.ring-1 {
width: 200px;
height: 200px;
}
.ring-2 {
width: 350px;
height: 350px;
}
.ring-3 {
width: 500px;
height: 500px;
}
}
@media (max-width: 480px) {
.hero-title {
font-size: clamp(3rem, 16vw, 5rem);
}
.section-title {
font-size: clamp(2rem, 9vw, 3rem);
}
.models-grid {
grid-template-columns: 1fr;
}
.model-card {
padding: 1.5rem 1rem 1rem;
}
.tech-visual-card {
width: 200px;
height: 240px;
padding: 1.5rem;
}
.tech-icon-svg {
width: 110px;
height: 110px;
}
.dashboard-screen {
max-width: 320px;
padding: 8px 10px;
}
.dash-speedo {
flex: 0 0 70px;
}
.speedo-arc {
width: 65px;
height: 45px;
}
.speedo-value {
font-size: 20px;
}
.dash-info {
flex: 0 0 70px;
}
.stat-number {
font-size: clamp(2.5rem, 10vw, 3.5rem);
}
.safety-feature {
flex-direction: column;
gap: 0.75rem;
padding: 1rem;
}
.btn-primary,
.btn-outline {
padding: 14px 32px;
width: 100%;
}
}
/* ═══════════════════════════════════════════════════════════════════════
REDUCED MOTION
═══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.scroll-line {
animation: none;
opacity: 0.5;
}
.pulse-ring {
animation: none;
}
.reveal {
opacity: 1;
transform: none;
}
.hero-title,
.hero-subtitle,
.hero-eyebrow,
.hero-actions,
.scroll-indicator {
opacity: 1;
}
.model-card {
opacity: 1;
transform: none;
}
.step-card.active {
animation: none;
}
.how-visual.active {
animation: none;
}
.model-card:hover {
transform: none;
}
.btn-primary:hover {
transform: none;
}
}/* ═══════════════════════════════════════════════════════════════════════
Tesla UHD Electric Vehicle Landing Page — Script
═══════════════════════════════════════════════════════════════════════ */
// ── Gradient Mesh Background (Canvas 2D) ───────────────────────────
(function () {
"use strict";
const canvas = document.getElementById("mesh-bg");
const ctx = canvas.getContext("2d");
const DPR = window.devicePixelRatio || 1;
let W, H;
function resize() {
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W * DPR;
canvas.height = H * DPR;
canvas.style.width = W + "px";
canvas.style.height = H + "px";
ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
}
resize();
window.addEventListener("resize", () => {
resize();
initOrbs();
});
const ORB_CONFIGS = [
// Red orbs — Tesla accent
{ color: "rgba(232,33,39,0.25)", fx: 0.2, fy: 0.18, ax: 0.3, ay: 0.25, px: 0.0, py: 0.0 },
{ color: "rgba(232,33,39,0.12)", fx: 0.15, fy: 0.3, ax: 0.35, ay: 0.28, px: 1.4, py: 0.9 },
// Blue orb — energy accent
{ color: "rgba(62,104,255,0.18)", fx: 0.35, fy: 0.12, ax: 0.28, ay: 0.35, px: 2.8, py: 1.6 },
// Dim red orb
{ color: "rgba(232,33,39,0.08)", fx: 0.12, fy: 0.4, ax: 0.4, ay: 0.2, px: 0.6, py: 3.2 },
];
let orbs = [];
function initOrbs() {
orbs = ORB_CONFIGS.map((cfg, i) => ({
...cfg,
cx: W * (0.15 + (i / ORB_CONFIGS.length) * 0.7),
cy: H * (0.2 + (i % 3) * 0.3),
r: Math.min(W, H) * (0.3 + Math.random() * 0.25),
}));
}
initOrbs();
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
let t = 0;
function draw() {
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, W, H);
ctx.globalCompositeOperation = "screen";
orbs.forEach((orb) => {
const speed = reducedMotion ? 0 : 1;
const x = orb.cx + Math.sin(t * orb.fx + orb.px) * orb.ax * W * speed;
const y = orb.cy + Math.cos(t * orb.fy + orb.py) * orb.ay * H * speed;
const g = ctx.createRadialGradient(x, y, 0, x, y, orb.r);
g.addColorStop(0, orb.color);
g.addColorStop(0.5, orb.color.replace(/[\d.]+\)$/, "0.06)"));
g.addColorStop(1, "transparent");
ctx.fillStyle = g;
ctx.fillRect(0, 0, W, H);
});
ctx.globalCompositeOperation = "source-over";
// Vignette
const vignette = ctx.createRadialGradient(W / 2, H / 2, H * 0.15, W / 2, H / 2, H * 0.85);
vignette.addColorStop(0, "transparent");
vignette.addColorStop(1, "rgba(0,0,0,0.6)");
ctx.fillStyle = vignette;
ctx.fillRect(0, 0, W, H);
t += 0.003;
requestAnimationFrame(draw);
}
draw();
})();
// ── Lenis Smooth Scroll ────────────────────────────────────────────
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
smoothWheel: true,
autoRaf: false,
});
gsap.registerPlugin(ScrollTrigger);
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const dur = (d) => (reduced ? 0 : d);
// ═══════════════════════════════════════════════════════════════════════
// HERO ENTRANCE
// ═══════════════════════════════════════════════════════════════════════
const heroTl = gsap.timeline({ defaults: { ease: "power4.out" }, delay: 0.4 });
heroTl
.to(".hero-eyebrow", {
opacity: 1,
duration: dur(1),
})
.to(
".hero-title",
{
opacity: 1,
duration: dur(2),
},
"-=0.6"
)
.to(
".hero-subtitle",
{
opacity: 1,
y: -10,
duration: dur(1.2),
},
"-=1.5"
)
.to(
".hero-actions",
{
opacity: 1,
y: -5,
duration: dur(1),
},
"-=0.8"
)
.to(
".scroll-indicator",
{
opacity: 1,
duration: dur(0.8),
},
"-=0.4"
);
// ═══════════════════════════════════════════════════════════════════════
// HERO PARALLAX ON SCROLL
// ═══════════════════════════════════════════════════════════════════════
gsap.to(".hero-content", {
scale: 1.15,
opacity: 0,
filter: "blur(12px)",
scrollTrigger: {
trigger: ".hero",
start: "top top",
end: "70% top",
scrub: true,
},
});
gsap.to(".hero-actions", {
y: -60,
opacity: 0,
scrollTrigger: {
trigger: ".hero",
start: "20% top",
end: "60% top",
scrub: true,
},
});
// ═══════════════════════════════════════════════════════════════════════
// GENERIC REVEAL (elements with .reveal class)
// ═══════════════════════════════════════════════════════════════════════
gsap.utils.toArray(".reveal").forEach((el) => {
gsap.fromTo(
el,
{ opacity: 0, y: reduced ? 0 : 40 },
{
opacity: 1,
y: 0,
duration: dur(1),
ease: "power3.out",
scrollTrigger: {
trigger: el,
start: "top 85%",
toggleActions: "play none none none",
},
}
);
});
// ═══════════════════════════════════════════════════════════════════════
// MODEL CARDS — stagger reveal
// ═══════════════════════════════════════════════════════════════════════
const modelCards = document.querySelectorAll(".model-card");
if (modelCards.length) {
gsap.fromTo(
modelCards,
{ opacity: 0, y: reduced ? 0 : 30, scale: reduced ? 1 : 0.96 },
{
opacity: 1,
y: 0,
scale: 1,
duration: dur(0.7),
stagger: 0.12,
ease: "power3.out",
scrollTrigger: {
trigger: ".models-grid",
start: "top 80%",
toggleActions: "play none none none",
},
}
);
}
// ═══════════════════════════════════════════════════════════════════════
// TECHNOLOGY — pinned scroll with step swap
// ═══════════════════════════════════════════════════════════════════════
const stepCards = document.querySelectorAll(".step-card");
const howVisuals = document.querySelectorAll(".how-visual");
const stepDots = document.querySelectorAll(".step-dot");
let activeStep = 0;
function setActiveStep(index) {
if (index === activeStep) return;
stepCards.forEach((c) => c.classList.remove("active"));
stepCards[index].classList.add("active");
howVisuals.forEach((v) => v.classList.remove("active"));
howVisuals[index].classList.add("active");
stepDots.forEach((d) => d.classList.remove("active"));
stepDots[index].classList.add("active");
activeStep = index;
}
ScrollTrigger.create({
trigger: ".how-track",
start: "top top",
end: "bottom bottom",
scrub: 0,
onUpdate: (self) => {
const p = self.progress;
if (p < 0.33) setActiveStep(0);
else if (p < 0.66) setActiveStep(1);
else setActiveStep(2);
},
});
// ═══════════════════════════════════════════════════════════════════════
// STATS — count-up animation
// ═══════════════════════════════════════════════════════════════════════
document.querySelectorAll(".stat-number").forEach((el) => {
const target = parseInt(el.dataset.target, 10);
const suffix = el.dataset.suffix || "";
if (isNaN(target)) return;
el.textContent = "0" + suffix;
ScrollTrigger.create({
trigger: el,
start: "top 85%",
once: true,
onEnter: () => {
gsap.to(
{ val: 0 },
{
val: target,
duration: dur(2),
ease: "power2.out",
onUpdate: function () {
const current = Math.round(this.targets()[0].val);
el.textContent = current.toLocaleString() + suffix;
},
}
);
},
});
});
// ═══════════════════════════════════════════════════════════════════════
// SAFETY FEATURES — stagger reveal
// ═══════════════════════════════════════════════════════════════════════
const safetyFeatures = document.querySelectorAll(".safety-feature");
if (safetyFeatures.length) {
gsap.fromTo(
safetyFeatures,
{ opacity: 0, x: reduced ? 0 : -20 },
{
opacity: 1,
x: 0,
duration: dur(0.6),
stagger: 0.15,
ease: "power3.out",
scrollTrigger: {
trigger: ".safety-features",
start: "top 80%",
toggleActions: "play none none none",
},
}
);
}
// ═══════════════════════════════════════════════════════════════════════
// DASHBOARD — mouse tilt parallax
// ═══════════════════════════════════════════════════════════════════════
const dashboardScreen = document.querySelector(".dash-device .dashboard-screen");
if (dashboardScreen && !reduced) {
// Subtle scroll parallax
gsap.to(dashboardScreen, {
y: -40,
rotateX: 5,
scrollTrigger: {
trigger: ".dashboard-section",
start: "top center",
end: "bottom center",
scrub: true,
},
});
// Mouse tilt
window.addEventListener("mousemove", (e) => {
const rect = dashboardScreen.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const x = (e.clientX - cx) / (rect.width / 2);
const y = (e.clientY - cy) / (rect.height / 2);
gsap.to(dashboardScreen, {
rotateY: x * 8,
rotateX: -y * 8,
duration: 0.8,
ease: "power2.out",
});
});
}
// ═══════════════════════════════════════════════════════════════════════
// CTA — rings + entrance
// ═══════════════════════════════════════════════════════════════════════
gsap.utils.toArray(".ring").forEach((ring, i) => {
gsap.fromTo(
ring,
{ scale: 0.5, opacity: 0 },
{
scale: 1,
opacity: 1,
duration: dur(1.5),
delay: i * 0.15,
scrollTrigger: {
trigger: ".cta-section",
start: "top 80%",
toggleActions: "play none none none",
},
}
);
});<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tesla | Electric. Exhilarating.</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- Gradient Mesh Background -->
<canvas id="mesh-bg"></canvas>
<main id="main">
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- HERO -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="hero">
<div class="hero-content">
<p class="hero-eyebrow">Tesla</p>
<h1 class="hero-title">Electric.<br>Exhilarating.</h1>
<p class="hero-subtitle">0–60 mph in 1.99 seconds. The quickest acceleration on earth.</p>
<div class="hero-actions">
<button class="btn-primary btn-glow">Order Now</button>
<button class="btn-outline">Test Drive</button>
</div>
</div>
<div class="scroll-indicator">
<span>Scroll</span>
<div class="scroll-line"></div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- MODEL LINEUP -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="models-section">
<div class="section-container">
<div class="section-header reveal">
<span class="tag">Lineup</span>
<h2 class="section-title">Choose your<br>Tesla</h2>
</div>
<div class="models-grid">
<!-- Model S — sedan -->
<div class="model-card">
<div class="model-silhouette">
<svg viewBox="0 0 200 80" fill="none" aria-hidden="true">
<!-- Sedan — low, sleek profile -->
<path d="M20 55 C20 55 30 52 45 50 C55 48 65 30 80 26 C95 22 120 22 140 26 C155 30 165 40 175 50 C180 52 185 55 185 55" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.06)"/>
<line x1="18" y1="55" x2="187" y2="55" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Roofline -->
<path d="M65 30 C75 22 85 18 105 17 C125 18 140 22 150 30" stroke="currentColor" stroke-width="1" opacity="0.4"/>
<!-- Windows -->
<path d="M72 30 L80 22 L120 20 L145 30" stroke="currentColor" stroke-width="0.8" fill="rgba(255,255,255,0.03)" opacity="0.5"/>
<!-- Wheels -->
<circle cx="55" cy="56" r="9" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="55" cy="56" r="4" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<circle cx="155" cy="56" r="9" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="155" cy="56" r="4" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<!-- Headlight -->
<path d="M178 48 L185 50" stroke="var(--ts-red)" stroke-width="1.5" opacity="0.8"/>
</svg>
</div>
<h3 class="model-name">Model S</h3>
<p class="model-spec">396 mi range</p>
<div class="model-meta">
<span class="model-stat">1.99s 0-60</span>
<span class="model-price">From $74,990</span>
</div>
</div>
<!-- Model X — SUV -->
<div class="model-card">
<div class="model-silhouette">
<svg viewBox="0 0 200 80" fill="none" aria-hidden="true">
<!-- SUV — taller, boxier -->
<path d="M22 58 C22 58 30 55 42 52 C50 48 58 24 75 18 C90 14 125 14 145 18 C160 24 168 40 178 52 C182 55 186 58 186 58" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.06)"/>
<line x1="20" y1="58" x2="188" y2="58" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Roofline — higher, flatter -->
<path d="M62 24 C70 14 82 10 100 9 C118 10 135 14 148 24" stroke="currentColor" stroke-width="1" opacity="0.4"/>
<!-- Windows -->
<path d="M68 24 L78 14 L130 12 L150 24" stroke="currentColor" stroke-width="0.8" fill="rgba(255,255,255,0.03)" opacity="0.5"/>
<!-- Falcon wing hint -->
<path d="M85 12 L90 6 L96 12" stroke="currentColor" stroke-width="0.6" opacity="0.25"/>
<!-- Wheels -->
<circle cx="55" cy="59" r="10" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="55" cy="59" r="5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<circle cx="158" cy="59" r="10" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="158" cy="59" r="5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<!-- Headlight -->
<path d="M180 48 L186 50" stroke="var(--ts-red)" stroke-width="1.5" opacity="0.8"/>
</svg>
</div>
<h3 class="model-name">Model X</h3>
<p class="model-spec">348 mi range</p>
<div class="model-meta">
<span class="model-stat">2.5s 0-60</span>
<span class="model-price">From $79,990</span>
</div>
</div>
<!-- Cybertruck — angular truck -->
<div class="model-card model-card-featured">
<div class="model-silhouette">
<svg viewBox="0 0 200 80" fill="none" aria-hidden="true">
<!-- Cybertruck — angular, geometric -->
<path d="M18 56 L40 56 L48 32 L80 14 L160 14 L170 32 L180 42 L185 56 L188 56" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.08)"/>
<line x1="16" y1="56" x2="190" y2="56" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Angular roofline -->
<path d="M48 32 L80 14 L160 14 L170 32" stroke="currentColor" stroke-width="1" opacity="0.5"/>
<!-- Bed line -->
<line x1="130" y1="14" x2="130" y2="32" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<!-- Window -->
<path d="M52 32 L82 16 L128 16 L128 32 Z" stroke="currentColor" stroke-width="0.8" fill="rgba(255,255,255,0.03)" opacity="0.4"/>
<!-- Wheels -->
<circle cx="58" cy="57" r="10" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="58" cy="57" r="5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<circle cx="162" cy="57" r="10" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="162" cy="57" r="5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<!-- Light bar -->
<line x1="18" y1="50" x2="38" y2="50" stroke="var(--ts-red)" stroke-width="2" opacity="0.6"/>
<line x1="180" y1="42" x2="188" y2="48" stroke="var(--ts-red)" stroke-width="2" opacity="0.6"/>
</svg>
</div>
<h3 class="model-name">Cybertruck</h3>
<p class="model-spec">340 mi range</p>
<div class="model-meta">
<span class="model-stat">2.6s 0-60</span>
<span class="model-price">From $60,990</span>
</div>
<span class="new-badge">New</span>
</div>
<!-- Roadster — ultra-sleek -->
<div class="model-card">
<div class="model-silhouette">
<svg viewBox="0 0 200 80" fill="none" aria-hidden="true">
<!-- Roadster — very low, aerodynamic -->
<path d="M22 54 C22 54 35 52 50 50 C60 46 72 34 90 30 C105 28 120 28 135 30 C150 34 162 42 172 50 C178 52 184 54 184 54" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.06)"/>
<line x1="20" y1="54" x2="186" y2="54" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Ultra-low roofline -->
<path d="M75 34 C85 26 95 24 108 24 C120 24 130 28 138 34" stroke="currentColor" stroke-width="1" opacity="0.4"/>
<!-- Windshield -->
<path d="M78 34 L90 26 L125 25 L140 34" stroke="currentColor" stroke-width="0.8" fill="rgba(255,255,255,0.03)" opacity="0.5"/>
<!-- Wheels -->
<circle cx="55" cy="55" r="8" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="55" cy="55" r="3.5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<circle cx="158" cy="55" r="8" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.04)"/>
<circle cx="158" cy="55" r="3.5" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<!-- Headlights -->
<path d="M176 48 L184 50" stroke="var(--ts-red)" stroke-width="1.5" opacity="0.8"/>
<path d="M22 50 L28 48" stroke="var(--ts-red)" stroke-width="1.5" opacity="0.8"/>
</svg>
</div>
<h3 class="model-name">Roadster</h3>
<p class="model-spec">620 mi range</p>
<div class="model-meta">
<span class="model-stat">1.9s 0-60</span>
<span class="model-price">From $200,000</span>
</div>
</div>
</div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- TECHNOLOGY (pinned) -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="how-track" id="technology">
<div class="how-sticky">
<div class="how-content">
<div class="step-dots">
<span class="step-dot active" data-step="0"></span>
<span class="step-dot" data-step="1"></span>
<span class="step-dot" data-step="2"></span>
</div>
<div class="step-card active" id="step-0">
<span class="tag">Autopilot</span>
<h2 class="step-heading">Full Self-Driving</h2>
<p class="step-desc">Navigate on Autopilot. Automatic lane changes, highway merging, and parking — all with zero driver input. The future of autonomous driving.</p>
</div>
<div class="step-card" id="step-1">
<span class="tag">Battery</span>
<h2 class="step-heading">4680 Cell Technology</h2>
<p class="step-desc">Five times more energy, six times more power, and 16% more range. Our tabless battery architecture redefines what's possible.</p>
</div>
<div class="step-card" id="step-2">
<span class="tag">Supercharging</span>
<h2 class="step-heading">15 Minutes to 200 mi</h2>
<p class="step-desc">The world's fastest charging network. 50,000+ Superchargers globally. Up to 250 kW — 200 miles of range in just 15 minutes.</p>
</div>
</div>
<!-- Visual side -->
<div class="how-visuals">
<!-- Autopilot: steering wheel -->
<div class="how-visual active" id="visual-0">
<div class="tech-visual-card">
<svg viewBox="0 0 160 160" fill="none" class="tech-icon-svg" aria-hidden="true">
<!-- Steering wheel -->
<circle cx="80" cy="80" r="55" stroke="currentColor" stroke-width="2" opacity="0.5"/>
<circle cx="80" cy="80" r="52" stroke="var(--ts-red)" stroke-width="1" opacity="0.3"/>
<!-- Wheel grip arcs -->
<path d="M30 95 A55 55 0 0 1 30 65" stroke="currentColor" stroke-width="6" stroke-linecap="round" opacity="0.7"/>
<path d="M130 65 A55 55 0 0 1 130 95" stroke="currentColor" stroke-width="6" stroke-linecap="round" opacity="0.7"/>
<path d="M55 130 A55 55 0 0 1 105 130" stroke="currentColor" stroke-width="6" stroke-linecap="round" opacity="0.7"/>
<!-- Center hub -->
<circle cx="80" cy="80" r="18" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.08)"/>
<text x="80" y="82" text-anchor="middle" dominant-baseline="middle" fill="currentColor" font-size="8" font-weight="600" letter-spacing="1">FSD</text>
<!-- Spoke lines -->
<line x1="62" y1="80" x2="28" y2="80" stroke="currentColor" stroke-width="1.2" opacity="0.3"/>
<line x1="98" y1="80" x2="132" y2="80" stroke="currentColor" stroke-width="1.2" opacity="0.3"/>
<!-- Pulsing ring -->
<circle cx="80" cy="80" r="65" stroke="var(--ts-red)" stroke-width="0.5" opacity="0.2" class="pulse-ring"/>
</svg>
<div class="tech-visual-label">Autonomous Navigation</div>
</div>
</div>
<!-- Battery: cell -->
<div class="how-visual" id="visual-1">
<div class="tech-visual-card">
<svg viewBox="0 0 160 160" fill="none" class="tech-icon-svg" aria-hidden="true">
<!-- Battery cell body -->
<rect x="45" y="30" width="70" height="105" rx="8" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.05)"/>
<!-- Terminal -->
<rect x="62" y="22" width="36" height="10" rx="4" stroke="currentColor" stroke-width="1.2" fill="rgba(255,255,255,0.04)"/>
<!-- Energy fill (gradient) -->
<rect x="50" y="60" width="60" height="70" rx="4" fill="url(#battGrad)" opacity="0.4"/>
<defs>
<linearGradient id="battGrad" x1="0" y1="1" x2="0" y2="0">
<stop offset="0%" stop-color="#E82127"/>
<stop offset="50%" stop-color="#3E68FF"/>
<stop offset="100%" stop-color="transparent"/>
</linearGradient>
</defs>
<!-- Cell segments -->
<line x1="50" y1="75" x2="110" y2="75" stroke="currentColor" stroke-width="0.5" opacity="0.2"/>
<line x1="50" y1="90" x2="110" y2="90" stroke="currentColor" stroke-width="0.5" opacity="0.2"/>
<line x1="50" y1="105" x2="110" y2="105" stroke="currentColor" stroke-width="0.5" opacity="0.2"/>
<!-- Energy level text -->
<text x="80" y="100" text-anchor="middle" fill="currentColor" font-size="16" font-weight="700">4680</text>
<text x="80" y="115" text-anchor="middle" fill="currentColor" font-size="7" opacity="0.5">CELL</text>
<!-- Pulse -->
<rect x="40" y="25" width="80" height="115" rx="12" stroke="var(--ts-red)" stroke-width="0.5" opacity="0.15" class="pulse-ring"/>
</svg>
<div class="tech-visual-label">Next-Gen Cell Architecture</div>
</div>
</div>
<!-- Supercharging: lightning bolt -->
<div class="how-visual" id="visual-2">
<div class="tech-visual-card">
<svg viewBox="0 0 160 160" fill="none" class="tech-icon-svg" aria-hidden="true">
<!-- Lightning bolt -->
<path d="M90 20 L65 75 L82 75 L70 140 L110 65 L90 65 L105 20 Z" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.12)" stroke-linejoin="round"/>
<!-- Inner bolt glow -->
<path d="M88 32 L72 70 L84 70 L75 128 L102 72 L90 72 L100 32 Z" fill="rgba(232,33,39,0.08)"/>
<!-- Charging arc left -->
<path d="M40 100 A45 45 0 0 1 40 60" stroke="var(--ts-blue)" stroke-width="1" opacity="0.3" stroke-dasharray="3 4"/>
<!-- Charging arc right -->
<path d="M120 60 A45 45 0 0 1 120 100" stroke="var(--ts-blue)" stroke-width="1" opacity="0.3" stroke-dasharray="3 4"/>
<!-- KW label -->
<text x="80" y="155" text-anchor="middle" fill="currentColor" font-size="8" font-weight="600" opacity="0.5">250 kW</text>
<!-- Pulse -->
<circle cx="80" cy="80" r="70" stroke="var(--ts-red)" stroke-width="0.5" opacity="0.15" class="pulse-ring"/>
</svg>
<div class="tech-visual-label">Ultra-Fast Charging</div>
</div>
</div>
</div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- STATS -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="stats-section">
<div class="section-container">
<div class="stats-grid">
<div class="stat-item reveal">
<div class="stat-number" data-target="2" data-suffix="M+">0</div>
<div class="stat-label">Vehicles Delivered</div>
<p class="stat-desc">Electric vehicles on roads worldwide</p>
</div>
<div class="stat-item reveal">
<div class="stat-number" data-target="50000" data-suffix="+">0</div>
<div class="stat-label">Superchargers</div>
<p class="stat-desc">The world's fastest charging network</p>
</div>
<div class="stat-item reveal">
<div class="stat-number" data-target="400" data-suffix="+ mi">0</div>
<div class="stat-label">Maximum Range</div>
<p class="stat-desc">On a single charge — no compromises</p>
</div>
</div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- SAFETY -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="safety-section">
<div class="section-container">
<div class="safety-card glass-card reveal">
<div class="safety-header">
<div class="safety-icon">
<svg viewBox="0 0 48 48" fill="none" aria-hidden="true">
<path d="M24 4L6 12v12c0 11.1 7.7 21.5 18 24 10.3-2.5 18-12.9 18-24V12L24 4z" stroke="currentColor" stroke-width="1.5" fill="rgba(232,33,39,0.1)"/>
<path d="M18 24l4 4 8-8" stroke="var(--ts-red)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<h2 class="section-title">5-Star Safety.<br>Every Model.</h2>
<p class="text-muted">The lowest probability of injury of any car ever tested by NHTSA.</p>
</div>
<div class="safety-stars" aria-label="5 out of 5 stars">
<svg viewBox="0 0 24 24" fill="var(--ts-red)" width="20" height="20"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>
<svg viewBox="0 0 24 24" fill="var(--ts-red)" width="20" height="20"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>
<svg viewBox="0 0 24 24" fill="var(--ts-red)" width="20" height="20"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>
<svg viewBox="0 0 24 24" fill="var(--ts-red)" width="20" height="20"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>
<svg viewBox="0 0 24 24" fill="var(--ts-red)" width="20" height="20"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>
</div>
<div class="safety-features">
<div class="safety-feature">
<div class="sf-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<circle cx="12" cy="12" r="10"/>
<path d="M12 8v4l3 3"/>
</svg>
</div>
<div>
<h4 class="sf-title">360° Awareness</h4>
<p class="text-muted text-sm">8 cameras, 12 ultrasonic sensors — complete environmental coverage at all times.</p>
</div>
</div>
<div class="safety-feature">
<div class="sf-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
</div>
<div>
<h4 class="sf-title">Collision Avoidance</h4>
<p class="text-muted text-sm">Automatic emergency braking, front collision warning, and side collision avoidance.</p>
</div>
</div>
<div class="safety-feature">
<div class="sf-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<path d="M2 12h5l2-7 3 14 3-10 2 3h5"/>
</svg>
</div>
<div>
<h4 class="sf-title">Crash Energy Absorption</h4>
<p class="text-muted text-sm">Rigid passenger cell with front and rear crumple zones — 40% less injury risk.</p>
</div>
</div>
<div class="safety-feature">
<div class="sf-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>
</svg>
</div>
<div>
<h4 class="sf-title">Sentry Mode</h4>
<p class="text-muted text-sm">Continuous monitoring and recording when parked. Alerts sent to your phone.</p>
</div>
</div>
<div class="safety-feature">
<div class="sf-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<path d="M9 3H5a2 2 0 00-2 2v4m6-6h10a2 2 0 012 2v4M9 3v18m0 0h10a2 2 0 002-2v-4M9 21H5a2 2 0 01-2-2v-4"/>
</svg>
</div>
<div>
<h4 class="sf-title">Cabin Overheat Protection</h4>
<p class="text-muted text-sm">Automatic climate control keeps the cabin below 105°F, protecting passengers and pets.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- DASHBOARD SHOWCASE -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="dashboard-section">
<div class="section-container dash-grid">
<div class="dash-text reveal">
<span class="tag">Interface</span>
<h2 class="section-title">The smartest<br>dashboard</h2>
<p class="text-muted">A 15" cinematic touchscreen. Everything from navigation to entertainment, climate to vehicle controls — at your fingertips.</p>
</div>
<div class="dash-device reveal">
<div class="dashboard-screen">
<!-- Top bar -->
<div class="dash-topbar">
<span class="dash-time">9:41</span>
<span class="dash-temp-ambient">72°F</span>
<div class="dash-signal-bars">
<span></span><span></span><span></span><span></span>
</div>
</div>
<!-- Main layout: left speed, center map/car, right info -->
<div class="dash-main">
<!-- Left: speedometer -->
<div class="dash-speedo">
<div class="speedo-arc">
<svg viewBox="0 0 120 80" class="speedo-svg">
<!-- Background arc -->
<path d="M15 70 A50 50 0 0 1 105 70" stroke="rgba(255,255,255,0.08)" stroke-width="4" fill="none" stroke-linecap="round"/>
<!-- Active arc (red gradient) -->
<path d="M15 70 A50 50 0 0 1 75 22" stroke="url(#speedGrad)" stroke-width="4" fill="none" stroke-linecap="round"/>
<defs>
<linearGradient id="speedGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--ts-blue)"/>
<stop offset="100%" stop-color="var(--ts-red)"/>
</linearGradient>
</defs>
</svg>
</div>
<div class="speedo-value">73</div>
<div class="speedo-unit">mph</div>
<div class="speedo-gear">D</div>
</div>
<!-- Center: car top-view -->
<div class="dash-center">
<div class="dash-car-topview">
<svg viewBox="0 0 80 160" fill="none" aria-hidden="true">
<!-- Car body outline — top-down view -->
<path d="M25 140 C20 135 18 120 18 100 L18 60 C18 40 22 30 30 20 C35 14 38 12 40 12 L40 12 C42 12 45 14 50 20 C58 30 62 40 62 60 L62 100 C62 120 60 135 55 140 Z" stroke="currentColor" stroke-width="1.2" fill="rgba(255,255,255,0.03)"/>
<!-- Windshield -->
<path d="M28 42 C32 30 36 26 40 26 C44 26 48 30 52 42" stroke="currentColor" stroke-width="0.8" fill="rgba(62,104,255,0.06)" opacity="0.6"/>
<!-- Rear window -->
<path d="M30 118 C34 128 37 130 40 130 C43 130 46 128 50 118" stroke="currentColor" stroke-width="0.8" fill="rgba(62,104,255,0.06)" opacity="0.6"/>
<!-- Center line -->
<line x1="40" y1="16" x2="40" y2="136" stroke="currentColor" stroke-width="0.3" opacity="0.15"/>
<!-- Wheels -->
<rect x="12" y="38" width="6" height="18" rx="2" stroke="currentColor" stroke-width="0.8" fill="rgba(232,33,39,0.15)"/>
<rect x="62" y="38" width="6" height="18" rx="2" stroke="currentColor" stroke-width="0.8" fill="rgba(232,33,39,0.15)"/>
<rect x="12" y="104" width="6" height="18" rx="2" stroke="currentColor" stroke-width="0.8" fill="rgba(232,33,39,0.15)"/>
<rect x="62" y="104" width="6" height="18" rx="2" stroke="currentColor" stroke-width="0.8" fill="rgba(232,33,39,0.15)"/>
<!-- Headlights -->
<ellipse cx="28" cy="16" rx="4" ry="2" fill="rgba(232,33,39,0.3)"/>
<ellipse cx="52" cy="16" rx="4" ry="2" fill="rgba(232,33,39,0.3)"/>
</svg>
</div>
<!-- Route line overlay -->
<div class="dash-route">
<div class="route-line"></div>
<div class="route-dot route-dot-start"></div>
<div class="route-dot route-dot-end"></div>
</div>
</div>
<!-- Right: info panel -->
<div class="dash-info">
<!-- Battery -->
<div class="dash-battery">
<div class="battery-label">Battery</div>
<div class="battery-bar">
<div class="battery-fill"></div>
</div>
<div class="battery-pct">78%</div>
<div class="battery-range">312 mi</div>
</div>
<!-- Climate -->
<div class="dash-climate">
<div class="climate-label">Climate</div>
<div class="climate-temps">
<div class="climate-driver">
<span class="climate-val">70°</span>
<span class="climate-side">L</span>
</div>
<div class="climate-divider"></div>
<div class="climate-passenger">
<span class="climate-val">72°</span>
<span class="climate-side">R</span>
</div>
</div>
</div>
</div>
</div>
<!-- Bottom nav -->
<div class="dash-bottom">
<div class="dash-nav-btn active">
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14"><circle cx="8" cy="8" r="3"/><path d="M8 1v2M8 13v2M1 8h2M13 8h2" stroke="currentColor" stroke-width="1.2"/></svg>
</div>
<div class="dash-nav-btn">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" width="14" height="14"><path d="M2 6l6-4 6 4v7a1 1 0 01-1 1H3a1 1 0 01-1-1V6z"/></svg>
</div>
<div class="dash-nav-btn">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" width="14" height="14"><circle cx="8" cy="8" r="6"/><path d="M8 5v3l2 2"/></svg>
</div>
<div class="dash-nav-btn">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" width="14" height="14"><path d="M3 5h10M3 8h10M3 11h10"/></svg>
</div>
</div>
</div>
<div class="device-glow"></div>
</div>
</div>
</section>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- FINAL CTA -->
<!-- ═══════════════════════════════════════════════════════════ -->
<section class="cta-section">
<div class="cta-rings" aria-hidden="true">
<div class="ring ring-1"></div>
<div class="ring ring-2"></div>
<div class="ring ring-3"></div>
</div>
<div class="cta-orbs" aria-hidden="true">
<div class="cta-orb cta-orb-1"></div>
<div class="cta-orb cta-orb-2"></div>
</div>
<h2 class="section-title cta-title reveal">Experience<br>the future</h2>
<p class="text-muted cta-subtitle reveal">The revolution is electric. Join millions already driving Tesla.</p>
<div class="cta-buttons reveal">
<button class="btn-primary btn-glow">Order Now</button>
<button class="btn-outline">Schedule Test Drive</button>
</div>
</section>
</main>
<!-- Dependencies (same CDN pattern as lgc-80) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lenis@1.1.18/dist/lenis.min.js"></script>
<script src="./script.js"></script>
</body>
</html>Tesla UHD Electric Vehicle Landing Page
A premium, ultra-high-definition landing page inspired by Tesla’s ultra-minimal design language with red accents.
Highlights
- Animated gradient mesh — Canvas 2D background with red/blue energy orbs
- Glassmorphism model cards — Frosted-glass cards with CSS-only vehicle silhouettes
- Scroll-pinned Technology section — Autopilot, Battery, Supercharging reveals
- Animated stat counters — Vehicles, Superchargers, range stats
- CSS-only dashboard mockup — Touchscreen UI with speedometer and controls
- Smooth scroll — Lenis-powered throughout
Sections
- Hero — Canvas gradient mesh background with red/blue orbs, massive headline, dual CTA buttons, scroll indicator
- Model Lineup — Grid of glassmorphism cards with CSS-only vehicle silhouettes, model name, range, price
- Technology — Pinned 300vh section with 3-step walkthrough (Autopilot, Battery, Supercharging) and technical visuals
- Stats Counter — Animated numbers for vehicles delivered, Superchargers, and range with scroll-triggered count-up
- Safety — Glass card layout for 5-star rating, autonomous features, and crash avoidance stats
- Dashboard Showcase — CSS-only car dashboard/touchscreen mockup with speedometer, navigation, battery, and mouse-tilt parallax
- Final CTA — Expanding red rings with gradient orbs and experience prompt
Tech Stack
- GSAP & ScrollTrigger — High-performance scroll-driven animations and pinned sections
- Lenis — Smooth, inertial scrolling
- Canvas 2D — Animated gradient mesh background with drifting orbs
- Vanilla CSS3 — Glassmorphism, custom properties, gradient vehicle silhouettes, dashboard mockup
- Responsive — Breakpoints at 1024px, 768px, and 480px