"use client"; import React, { useEffect, useRef, useState } from "react"; import dynamic from "next/dynamic"; import { motion, useMotionValue, useTransform } from "framer-motion"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; const PerformanceCanvas = dynamic(() => import("./PerformanceCanvas"), { ssr: false }); export default function PerformanceSection() { const containerRef = useRef(null); const progressRef = useRef(0); const scroll = useMotionValue(0); const [pinState, setPinState] = useState<"before" | "pinned" | "after">("before"); const [mountScene, setMountScene] = useState(false); const [sceneActive, setSceneActive] = useState(false); const [isMobile, setIsMobile] = useState(false); const [reduced, setReduced] = useState(false); useEffect(() => { const mqMobile = window.matchMedia("(max-width: 767px)"); const mqReduce = window.matchMedia("(prefers-reduced-motion: reduce)"); const sync = () => { setIsMobile(mqMobile.matches); setReduced(mqReduce.matches); }; sync(); mqMobile.addEventListener("change", sync); mqReduce.addEventListener("change", sync); return () => { mqMobile.removeEventListener("change", sync); mqReduce.removeEventListener("change", sync); }; }, []); useEffect(() => { const el = containerRef.current; if (!el) return; const mountIo = new IntersectionObserver( (entries) => { if (entries.some((e) => e.isIntersecting)) { setMountScene(true); setSceneActive(true); mountIo.disconnect(); } }, { rootMargin: "120% 0px" }, ); const activeIo = new IntersectionObserver( (entries) => setSceneActive(entries.some((e) => e.isIntersecting)), { rootMargin: "10% 0px" }, ); mountIo.observe(el); activeIo.observe(el); return () => { mountIo.disconnect(); activeIo.disconnect(); }; }, []); useEffect(() => { const el = containerRef.current; if (!el) return; gsap.registerPlugin(ScrollTrigger); let lastPin: "before" | "pinned" | "after" = "before"; const st = ScrollTrigger.create({ trigger: el, start: "top top", end: "bottom bottom", scrub: 0.4, invalidateOnRefresh: true, onUpdate: (self) => { const p = self.progress; progressRef.current = p; scroll.set(p); const ns = p <= 0.0002 ? "before" : p >= 0.9998 ? "after" : "pinned"; if (ns !== lastPin) { lastPin = ns; setPinState(ns); } }, }); const refresh = setTimeout(() => ScrollTrigger.refresh(), 300); return () => { clearTimeout(refresh); st.kill(); }; }, [scroll]); const beforeOpacity = useTransform(scroll, [0.1, 0.3, 0.46], [0.4, 1, 0.32]); const afterOpacity = useTransform(scroll, [0.6, 0.74, 0.95], [0.32, 1, 0.7]); const stageA = useTransform(scroll, [0, 0.4], [1, 0]); const stageB = useTransform(scroll, [0.4, 0.55, 0.65], [0, 1, 0]); const stageC = useTransform(scroll, [0.65, 0.85], [0, 1]); return (
{mountScene && (
)}
Results & Impact What MileTruth Delivers From congested traditional dispatch to a lean optimized fleet — the measurable business results across a live delivery city.
Traditional dispatch Transformation gateway Optimized network
Traditional Dispatch Congestion · long routes · fuel waste · delays MileTruth Optimized Clean corridors · organized fleet · faster coverage
); } const styles = ` .dm-perf { position: relative; height: 250vh; background: transparent; margin-bottom: 120px; } .dm-perf-sticky { position: absolute; top: 0; left: 0; width: 100%; height: 100vh; overflow: hidden; } .dm-perf.is-pinned .dm-perf-sticky { position: fixed; top: 0; left: 0; } .dm-perf.is-after .dm-perf-sticky { position: absolute; top: auto; bottom: 0; } .dm-perf-card { position: absolute !important; top: 110px !important; left: 40px !important; right: 40px !important; bottom: 24px !important; border-radius: 60px !important; overflow: hidden !important; background: linear-gradient(168deg, #1b1f26 0%, #15181d 45%, #101216 100%) !important; border: 1.5px solid rgba(255,255,255,0.08) !important; box-shadow: 0 4px 30px -4px rgba(0,0,0,0.7), 0 20px 80px -20px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.05) !important; box-sizing: border-box !important; } @media (max-width: 1024px) { .dm-perf-card { top: 96px !important; left: 20px !important; right: 20px !important; bottom: 16px !important; border-radius: 42px !important; } } @media (max-width: 767px) { .dm-perf-card { top: 86px !important; left: 10px !important; right: 10px !important; bottom: 10px !important; border-radius: 28px !important; } } .dm-perf-backdrop { position: absolute; inset: 0; z-index: 0; background: radial-gradient(55% 50% at 20% 60%, rgba(239,68,68,0.07) 0%, transparent 60%), radial-gradient(55% 50% at 80% 60%, rgba(34,197,94,0.08) 0%, transparent 60%); } .dm-perf-canvas { position: absolute; inset: 0; z-index: 1; } .dm-perf-canvas canvas { display: block; } .dm-perf-vignette { position: absolute; inset: 0; z-index: 2; pointer-events: none; background: radial-gradient(125% 105% at 50% 46%, transparent 56%, rgba(8,9,12,0.86) 100%), linear-gradient(180deg, rgba(8,9,12,0.5) 0%, transparent 20%, transparent 66%, rgba(8,9,12,0.9) 100%); } .dm-perf-ui { position: absolute; inset: 0; z-index: 4; pointer-events: none; font-family: var(--font-space-grotesk), var(--font-manrope), system-ui, sans-serif; } .dm-perf-head { position: absolute; top: clamp(18px, 3.4vh, 40px); left: 50%; transform: translateX(-50%); width: min(700px, 92vw); text-align: center; } .dm-perf-eyebrow { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; letter-spacing: 0.24em; text-transform: uppercase; color: #4ade80; padding: 5px 14px; border-radius: 999px; background: rgba(34,197,94,0.08); border: 1px solid rgba(34,197,94,0.28); backdrop-filter: blur(8px); } .dm-perf-dot { width: 6px; height: 6px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 10px #22c55e; } .dm-perf .dm-perf-head h2 { margin: 10px 0 6px !important; padding: 0 !important; color: #F8FAFC !important; font-weight: 700 !important; text-transform: none !important; font-size: clamp(22px, 2.6vw, 38px) !important; line-height: 1.08 !important; letter-spacing: -0.015em !important; } .dm-perf .dm-perf-head p { margin: 0 auto !important; padding: 0 !important; color: rgba(226,232,240,0.66) !important; max-width: 500px; font-size: clamp(11px, 1vw, 13.5px) !important; line-height: 1.45 !important; } .dm-perf-status { display: inline-flex; align-items: center; gap: 16px; margin-top: 12px; min-height: 18px; } .dm-perf-status__item { position: relative; display: inline-flex; align-items: center; gap: 7px; font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; color: #E2E8F0; font-weight: 600; } .dm-perf-status__item:not(:first-child) { position: absolute; left: 50%; transform: translateX(-50%); white-space: nowrap; } .dm-perf-status__dot { width: 6px; height: 6px; border-radius: 50%; } .dm-perf-status__dot--red { background: #ef4444; box-shadow: 0 0 10px #ef4444; } .dm-perf-status__dot--amber { background: #fbbf24; box-shadow: 0 0 10px #fbbf24; } .dm-perf-status__dot--green { background: #22c55e; box-shadow: 0 0 10px #22c55e; } .dm-perf-label { position: absolute; top: 44%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 4px; } .dm-perf-label--before { left: clamp(16px, 4vw, 60px); text-align: left; } .dm-perf-label--after { right: clamp(16px, 4vw, 60px); text-align: right; align-items: flex-end; } .dm-perf-label__tag { font-size: clamp(17px, 2vw, 28px); font-weight: 800; letter-spacing: -0.02em; color: #f87171; text-shadow: 0 0 22px rgba(239,68,68,0.45); } .dm-perf-label__tag--good { color: #4ade80; text-shadow: 0 0 22px rgba(34,197,94,0.5); } .dm-perf-label__sub { font-size: 10.5px; letter-spacing: 0.05em; color: rgba(226,232,240,0.6); max-width: 180px; } @media (max-width: 767px) { .dm-perf { height: 220vh; } .dm-perf-label__sub { display: none; } .dm-perf-label__tag { font-size: 15px; } .dm-perf-head h2 { font-size: 22px; } .dm-perf-status { gap: 10px; } } `;