update miletruth page and remove unwanted files

This commit is contained in:
2026-06-03 13:42:12 +05:30
parent 3bad62851c
commit 6eea5636fb
153 changed files with 6089 additions and 36024 deletions

View File

@@ -12,18 +12,7 @@ type Props = {
const COUNT_START = 0.7;
const COUNT_END = 0.97;
function Metric({ kpi, scroll, index }: { kpi: Kpi; scroll: MotionValue<number>; index: number }) {
const [jitter, setJitter] = React.useState(0);
React.useEffect(() => {
const interval = setInterval(() => {
// Tiny micro-fluctuation between -0.4% and +0.4%
const val = (Math.random() - 0.5) * 0.008;
setJitter(val);
}, 800 + Math.random() * 600); // slightly staggered updates
return () => clearInterval(interval);
}, []);
function Metric({ kpi, scroll, index, jitter }: { kpi: Kpi; scroll: MotionValue<number>; index: number; jitter: number }) {
// Single reactive string — updates without re-rendering React.
const value = useTransform(scroll, (v) => {
const t = Math.min(1, Math.max(0, (v - COUNT_START) / (COUNT_END - COUNT_START)));
@@ -140,10 +129,24 @@ function Metric({ kpi, scroll, index }: { kpi: Kpi; scroll: MotionValue<number>;
const MetricCard = React.memo(Metric);
function MetricsPanel({ scroll }: Props) {
// One shared interval drives the live "operational" micro-fluctuation for all
// cards (was 5 independent timers). Paused under reduced-motion and when the
// tab is hidden.
const [jitters, setJitters] = React.useState<number[]>(() => KPIS.map(() => 0));
React.useEffect(() => {
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const id = setInterval(() => {
if (document.hidden) return;
setJitters(KPIS.map(() => (Math.random() - 0.5) * 0.008));
}, 1100);
return () => clearInterval(id);
}, []);
return (
<div className="dm-opt-metrics" role="group" aria-label="Optimization results">
{KPIS.map((kpi, i) => (
<MetricCard key={kpi.key} kpi={kpi} scroll={scroll} index={i} />
<MetricCard key={kpi.key} kpi={kpi} scroll={scroll} index={i} jitter={jitters[i]} />
))}
</div>
);

View File

@@ -2,7 +2,7 @@
import React, { useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { EffectComposer, Bloom, Vignette } from "@react-three/postprocessing";
import { EffectComposer, Bloom } from "@react-three/postprocessing";
import { KernelSize } from "postprocessing";
import { COLORS } from "./constants";
import { damp, lerp } from "./math";
@@ -47,7 +47,7 @@ function OptimizationCanvas({ progress, reduced = false, isMobile = false, activ
return (
<Canvas
flat
dpr={[1, isMobile || reduced ? 1.3 : 1.6]}
dpr={[1, isMobile || reduced ? 1.25 : 1.5]}
camera={{ position: [0, 9, 19], fov: 50, near: 0.1, far: 120 }}
gl={{ antialias: !isMobile, powerPreference: "high-performance", alpha: false }}
frameloop={active ? "always" : "never"}
@@ -74,7 +74,6 @@ function OptimizationCanvas({ progress, reduced = false, isMobile = false, activ
radius={isMobile ? 0.6 : 0.75}
kernelSize={KernelSize.MEDIUM}
/>
<Vignette eskil={false} offset={0.25} darkness={0.5} />
</EffectComposer>
)}
</Canvas>

View File

@@ -5,7 +5,6 @@ import dynamic from "next/dynamic";
import { motion, AnimatePresence, useMotionValue, useTransform } from "framer-motion";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import Lenis from "lenis";
import {
COLORS,
PHASE_LABELS,
@@ -130,7 +129,7 @@ export default function OptimizationSection() {
mountIo.disconnect();
}
},
{ rootMargin: "120% 0px" },
{ rootMargin: "70% 0px" },
);
const activeIo = new IntersectionObserver(
(entries) => setSceneActive(entries.some((e) => e.isIntersecting)),
@@ -155,23 +154,11 @@ export default function OptimizationSection() {
if (!el) return;
gsap.registerPlugin(ScrollTrigger);
// Smooth scroll (Lenis), driven by a SINGLE rAF source — GSAP's ticker.
// Previously lenis.raf() was called from both a manual requestAnimationFrame
// loop AND gsap.ticker, double-stepping the integrator every frame, which is
// what made scrolling stutter. One source keeps Lenis + ScrollTrigger locked.
const lenis = new Lenis({
duration: 1.05,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
orientation: "vertical",
gestureOrientation: "vertical",
smoothWheel: true,
});
lenis.on("scroll", ScrollTrigger.update);
const tickerCb = (time: number) => lenis.raf(time * 1000); // ticker is in seconds, Lenis wants ms
gsap.ticker.add(tickerCb);
gsap.ticker.lagSmoothing(0);
// NOTE: /miletruth runs on native scroll (no Lenis). Smooth-scrolling this
// page fought the three stacked pinned WebGL sections and caused scroll lag;
// global Lenis (src/animations/SmoothScroll.tsx) is intentionally disabled on
// this route. ScrollTrigger's scrub + self-managed fixed pin work as-is on
// native scroll.
let lastPhase: PhaseKey = "chaos";
let lastPin: "before" | "pinned" | "after" = "before";
const st = ScrollTrigger.create({
@@ -201,8 +188,6 @@ export default function OptimizationSection() {
return () => {
clearTimeout(refresh);
st.kill();
gsap.ticker.remove(tickerCb);
lenis.destroy();
};
}, [scroll]);
@@ -211,7 +196,8 @@ export default function OptimizationSection() {
const leftBlur = useTransform(scroll, [0.3, 0.55], [0, 3]);
const leftFilter = useTransform(leftBlur, (b) => `blur(${b}px)`);
const rightOpacity = useTransform(scroll, [0.42, 0.66], [0.36, 1]);
const scanWidth = useTransform(scroll, [0, 1], ["0%", "100%"]);
// GPU transform (scaleX) instead of animating width, which forces layout each frame.
const scanScaleX = useTransform(scroll, [0, 1], [0, 1]);
const scanLineY = useTransform(scroll, [0.2, 0.42], ["8%", "92%"]);
const scanLineOpacity = useTransform(scroll, [0.18, 0.22, 0.42, 0.46], [0, 1, 1, 0]);
const dividerOpacity = useTransform(scroll, [0.45, 0.6], [0.15, 0.75]);
@@ -350,7 +336,7 @@ export default function OptimizationSection() {
{/* Scan progress bar */}
<div className="dm-opt-progress">
<div className="dm-opt-progress__track">
<motion.div className="dm-opt-progress__fill" style={{ width: scanWidth }} />
<motion.div className="dm-opt-progress__fill" style={{ scaleX: scanScaleX }} />
</div>
</div>
</header>
@@ -470,17 +456,20 @@ const styles = `
}
/* Animated subtle grid pattern */
.dm-opt-card::before {
content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
/* Expanded one tile beyond the (clipped) card so we can drift it via a GPU
transform instead of animating background-position (which repaints each frame). */
content: ""; position: absolute; inset: -60px; z-index: 0; pointer-events: none;
opacity: 0.035;
background-image:
linear-gradient(${rgba(COLORS.cyan, 0.5)} 1px, transparent 1px),
linear-gradient(90deg, ${rgba(COLORS.cyan, 0.5)} 1px, transparent 1px);
background-size: 60px 60px;
animation: dmOptGridDrift 25s linear infinite;
will-change: transform;
}
@keyframes dmOptGridDrift {
0% { background-position: 0 0; }
100% { background-position: 60px 60px; }
0% { transform: translate3d(0, 0, 0); }
100% { transform: translate3d(60px, 60px, 0); }
}
/* Radial center glow behind 3D scene */
.dm-opt-card::after {
@@ -669,7 +658,7 @@ const styles = `
background: ${rgba(COLORS.cyan, 0.10)}; max-width: 420px; margin: 0 auto;
}
.dm-opt-progress__fill {
height: 100%; border-radius: 999px;
height: 100%; width: 100%; transform-origin: left center; border-radius: 999px;
background: linear-gradient(90deg, ${COLORS.cyan}, ${COLORS.green});
box-shadow: 0 0 12px ${rgba(COLORS.cyan, 0.6)};
}
@@ -697,9 +686,10 @@ const styles = `
.dm-opt-panel {
pointer-events: auto; width: clamp(230px, 26vw, 340px);
padding: 18px 20px; border-radius: 20px;
background: ${rgba(COLORS.ink, 0.72)};
background: ${rgba(COLORS.ink, 0.92)};
border: 1px solid ${rgba(COLORS.slate, 0.22)};
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
/* backdrop blur removed — panel opacity is scroll-driven, so the blur was
recomputed every scroll frame; a near-opaque fill reads the same and is free. */
}
.dm-opt-panel--bad {
border-color: ${rgba(COLORS.red, 0.45)};
@@ -772,9 +762,9 @@ const styles = `
}
.dm-opt-metric {
position: relative; padding: 14px 14px 12px; border-radius: 16px;
background: ${rgba(COLORS.ink, 0.72)};
background: ${rgba(COLORS.ink, 0.92)};
border: 1px solid ${rgba(COLORS.slate, 0.25)};
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
/* backdrop blur removed — 5 metric cards animate on scroll; per-frame blur recompute was a hotspot. */
overflow: hidden;
opacity: 0; transform: translateY(22px);
animation: dmOptCardIn 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;

View File

@@ -0,0 +1,58 @@
import { rgba, phaseFromProgress, PHASES, PHASE_LABELS, type PhaseKey } from "./constants";
describe("optimization/constants — rgba()", () => {
it("converts a hex string to an rgba() string", () => {
expect(rgba("#22C55E", 0.5)).toBe("rgba(34, 197, 94, 0.5)");
expect(rgba("#000000", 1)).toBe("rgba(0, 0, 0, 1)");
expect(rgba("#FFFFFF", 0)).toBe("rgba(255, 255, 255, 0)");
});
it("is case-insensitive for hex digits", () => {
expect(rgba("#ffffff", 1)).toBe(rgba("#FFFFFF", 1));
});
});
describe("optimization/constants — phaseFromProgress()", () => {
it("returns the right phase at each threshold", () => {
expect(phaseFromProgress(PHASES.chaos)).toBe("chaos");
expect(phaseFromProgress(PHASES.scan)).toBe("scan");
expect(phaseFromProgress(PHASES.dissolve)).toBe("dissolve");
expect(phaseFromProgress(PHASES.optimize)).toBe("optimize");
expect(phaseFromProgress(PHASES.reorganize)).toBe("reorganize");
expect(phaseFromProgress(PHASES.metrics)).toBe("metrics");
});
it("returns the previous phase just below a threshold", () => {
expect(phaseFromProgress(PHASES.scan - 0.001)).toBe("chaos");
expect(phaseFromProgress(PHASES.dissolve - 0.001)).toBe("scan");
expect(phaseFromProgress(PHASES.metrics - 0.001)).toBe("reorganize");
});
it("handles the 0 and 1 extremes", () => {
expect(phaseFromProgress(0)).toBe("chaos");
expect(phaseFromProgress(1)).toBe("metrics");
});
it("only ever returns a defined phase key across a sweep", () => {
const keys = Object.keys(PHASES) as PhaseKey[];
for (let p = 0; p <= 1.0001; p += 0.02) {
expect(keys).toContain(phaseFromProgress(p));
}
});
});
describe("optimization/constants — phase tables", () => {
it("has strictly increasing phase thresholds", () => {
const vals = Object.values(PHASES);
for (let i = 1; i < vals.length; i++) {
expect(vals[i]).toBeGreaterThan(vals[i - 1]);
}
});
it("has a label for every phase key", () => {
for (const key of Object.keys(PHASES) as PhaseKey[]) {
expect(typeof PHASE_LABELS[key]).toBe("string");
expect(PHASE_LABELS[key].length).toBeGreaterThan(0);
}
});
});

View File

@@ -0,0 +1,99 @@
import { clamp01, lerp, remap, smoothstep, damp, seeded } from "./math";
describe("optimization/math — clamp01()", () => {
it("clamps to [0,1]", () => {
expect(clamp01(-2)).toBe(0);
expect(clamp01(0)).toBe(0);
expect(clamp01(0.37)).toBe(0.37);
expect(clamp01(1)).toBe(1);
expect(clamp01(5)).toBe(1);
});
});
describe("optimization/math — lerp()", () => {
it("interpolates linearly", () => {
expect(lerp(0, 10, 0)).toBe(0);
expect(lerp(0, 10, 1)).toBe(10);
expect(lerp(0, 10, 0.5)).toBe(5);
expect(lerp(2, 4, 0.25)).toBe(2.5);
});
it("extrapolates past the endpoints", () => {
expect(lerp(0, 10, 2)).toBe(20);
expect(lerp(0, 10, -1)).toBe(-10);
});
});
describe("optimization/math — remap()", () => {
it("remaps and clamps to the output range", () => {
expect(remap(5, 0, 10, 0, 100)).toBe(50);
expect(remap(-5, 0, 10, 0, 100)).toBe(0);
expect(remap(15, 0, 10, 0, 100)).toBe(100);
});
it("defaults the output range to [0,1]", () => {
expect(remap(2.5, 0, 10)).toBeCloseTo(0.25, 10);
});
it("guards against a zero-width input range (no NaN)", () => {
const v = remap(5, 2, 2, 0, 1);
expect(Number.isNaN(v)).toBe(false);
});
});
describe("optimization/math — smoothstep()", () => {
it("hits 0 and 1 at the edges and 0.5 at the middle", () => {
expect(smoothstep(0, 1, 0)).toBe(0);
expect(smoothstep(0, 1, 1)).toBe(1);
expect(smoothstep(0, 1, 0.5)).toBeCloseTo(0.5, 10);
});
it("clamps outside the edges", () => {
expect(smoothstep(0, 1, -1)).toBe(0);
expect(smoothstep(0, 1, 2)).toBe(1);
});
it("is monotonically non-decreasing", () => {
let prev = -Infinity;
for (let x = -0.2; x <= 1.2; x += 0.1) {
const v = smoothstep(0, 1, x);
expect(v).toBeGreaterThanOrEqual(prev);
prev = v;
}
});
it("guards against equal edges (no NaN)", () => {
expect(Number.isNaN(smoothstep(1, 1, 1))).toBe(false);
});
});
describe("optimization/math — damp()", () => {
it("does not move when dt is 0", () => {
expect(damp(3, 10, 5, 0)).toBe(3);
});
it("moves toward the target and converges with large lambda*dt", () => {
const once = damp(0, 10, 1, 0.5);
expect(once).toBeGreaterThan(0);
expect(once).toBeLessThan(10);
expect(damp(0, 10, 50, 1)).toBeCloseTo(10, 5);
});
});
describe("optimization/math — seeded()", () => {
it("is deterministic for a given input", () => {
expect(seeded(7)).toBe(seeded(7));
});
it("returns values within [0,1)", () => {
for (let i = 0; i < 200; i++) {
const v = seeded(i);
expect(v).toBeGreaterThanOrEqual(0);
expect(v).toBeLessThan(1);
}
});
it("produces different values for different seeds", () => {
expect(seeded(1)).not.toBe(seeded(2));
});
});