Skip to content

Commit f7c41d0

Browse files
committed
fix: remove Lenis, use native scroll
- removed @studio-freight/lenis (caused janky scroll) - removed scroll-linked parallax (too complex) - keep floating orbs with simple CSS animations - add CSS scroll-behavior: smooth - simplify headline stagger animation (remove blur) - native scroll feels better
1 parent 788a2d3 commit f7c41d0

6 files changed

Lines changed: 22 additions & 73 deletions

File tree

frontend/bun.lock

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"@radix-ui/react-switch": "^1.2.6",
2323
"@radix-ui/react-tabs": "^1.1.13",
2424
"@radix-ui/react-tooltip": "^1.2.8",
25-
"@studio-freight/lenis": "^1.0.42",
2625
"@supabase/supabase-js": "^2.39.0",
2726
"@tanstack/react-query": "^5.90.12",
2827
"@types/dagre": "^0.7.53",

frontend/src/components/landing/Hero.tsx

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useRef, useEffect, useState, useCallback } from 'react'
2-
import { motion, AnimatePresence, useScroll, useTransform, useSpring } from 'framer-motion'
2+
import { motion, AnimatePresence } from 'framer-motion'
33
import { Loader2, Sparkles } from 'lucide-react'
44
import { HeroSearch, type HeroSearchHandle } from './HeroSearch'
55
import { useDemoSearch, DEMO_REPOS, type DemoRepo } from '@/hooks/useDemoSearch'
@@ -24,22 +24,20 @@ const headlineVariants = {
2424
hidden: { opacity: 0 },
2525
visible: {
2626
opacity: 1,
27-
transition: { staggerChildren: 0.05, delayChildren: 0.2 }
27+
transition: { staggerChildren: 0.08, delayChildren: 0.2 }
2828
}
2929
}
3030

3131
const wordVariants = {
32-
hidden: { opacity: 0, y: 20, filter: 'blur(10px)' },
32+
hidden: { opacity: 0, y: 20 },
3333
visible: {
3434
opacity: 1,
3535
y: 0,
36-
filter: 'blur(0px)',
37-
transition: { duration: 0.5, ease: [0.25, 0.4, 0.25, 1] }
36+
transition: { duration: 0.4, ease: [0.25, 0.4, 0.25, 1] }
3837
}
3938
}
4039

4140
export function Hero({ onResultsReady }: Props) {
42-
const sectionRef = useRef<HTMLElement>(null)
4341
const searchRef = useRef<HeroSearchHandle>(null)
4442
const cardRef = useRef<HTMLDivElement>(null)
4543
const { query, repo, results, loading, searchTime, setQuery, setRepo, search } = useDemoSearch(false)
@@ -48,21 +46,6 @@ export function Hero({ onResultsReady }: Props) {
4846
const [typingIndex, setTypingIndex] = useState(0)
4947
const typingTimeoutRef = useRef<ReturnType<typeof setTimeout>>()
5048

51-
// Scroll-linked parallax
52-
const { scrollYProgress } = useScroll({
53-
target: sectionRef,
54-
offset: ['start start', 'end start']
55-
})
56-
57-
const smoothProgress = useSpring(scrollYProgress, { stiffness: 100, damping: 30 })
58-
const orb1Y = useTransform(smoothProgress, [0, 1], [0, -150])
59-
const orb2Y = useTransform(smoothProgress, [0, 1], [0, -100])
60-
const orb3Y = useTransform(smoothProgress, [0, 1], [0, -200])
61-
const orb1X = useTransform(smoothProgress, [0, 1], [0, 50])
62-
const orb2X = useTransform(smoothProgress, [0, 1], [0, -80])
63-
const contentY = useTransform(smoothProgress, [0, 1], [0, 100])
64-
const contentOpacity = useTransform(smoothProgress, [0, 0.5], [1, 0])
65-
6649
useEffect(() => {
6750
if (results.length) onResultsReady?.(results, query, repo.id, searchTime)
6851
}, [results, query, repo.id, searchTime, onResultsReady])
@@ -120,41 +103,33 @@ export function Hero({ onResultsReady }: Props) {
120103
const line2Words = ['unfamiliar', 'codebases.']
121104

122105
return (
123-
<section ref={sectionRef} className="relative min-h-[90vh] flex flex-col justify-center pt-16 pb-8 px-6 overflow-hidden">
106+
<section className="relative min-h-[90vh] flex flex-col justify-center pt-16 pb-8 px-6 overflow-hidden">
124107
{/* Grid pattern background */}
125108
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:64px_64px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,black_40%,transparent_100%)]" />
126109

127-
{/* Parallax gradient orbs */}
110+
{/* Floating gradient orbs */}
128111
<div className="absolute inset-0 overflow-hidden pointer-events-none">
129112
<motion.div
130113
className="absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full"
131-
style={{
132-
background: 'radial-gradient(circle, rgba(79,70,229,0.2) 0%, transparent 60%)',
133-
y: orb1Y,
134-
x: orb1X,
135-
}}
114+
style={{ background: 'radial-gradient(circle, rgba(79,70,229,0.2) 0%, transparent 60%)' }}
115+
animate={{ x: [0, 30, 0], y: [0, -20, 0] }}
116+
transition={{ duration: 10, repeat: Infinity, ease: 'easeInOut' }}
136117
/>
137118
<motion.div
138119
className="absolute top-1/3 right-1/4 w-[500px] h-[500px] rounded-full"
139-
style={{
140-
background: 'radial-gradient(circle, rgba(139,92,246,0.15) 0%, transparent 60%)',
141-
y: orb2Y,
142-
x: orb2X,
143-
}}
120+
style={{ background: 'radial-gradient(circle, rgba(139,92,246,0.15) 0%, transparent 60%)' }}
121+
animate={{ x: [0, -25, 0], y: [0, 25, 0] }}
122+
transition={{ duration: 12, repeat: Infinity, ease: 'easeInOut' }}
144123
/>
145124
<motion.div
146125
className="absolute bottom-1/4 left-1/3 w-[400px] h-[400px] rounded-full"
147-
style={{
148-
background: 'radial-gradient(circle, rgba(34,211,238,0.1) 0%, transparent 60%)',
149-
y: orb3Y,
150-
}}
126+
style={{ background: 'radial-gradient(circle, rgba(34,211,238,0.1) 0%, transparent 60%)' }}
127+
animate={{ x: [0, 20, 0], y: [0, -15, 0] }}
128+
transition={{ duration: 14, repeat: Infinity, ease: 'easeInOut' }}
151129
/>
152130
</div>
153131

154-
<motion.div
155-
className="relative max-w-3xl mx-auto w-full"
156-
style={{ y: contentY, opacity: contentOpacity }}
157-
>
132+
<div className="relative max-w-3xl mx-auto w-full">
158133
{/* Badge */}
159134
<motion.div
160135
className="flex justify-center mb-5"
@@ -356,7 +331,7 @@ export function Hero({ onResultsReady }: Props) {
356331
</div>
357332
<p className="text-xs text-muted-foreground/60">Works with any Python repository • Self-host or cloud</p>
358333
</motion.div>
359-
</motion.div>
334+
</div>
360335
</section>
361336
)
362337
}

frontend/src/hooks/useSmoothScroll.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

frontend/src/index.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
* Premium dark theme with glassmorphism
1111
*/
1212

13+
/* Smooth scroll */
14+
html {
15+
scroll-behavior: smooth;
16+
}
17+
1318
@layer base {
1419
:root {
1520
/* Background */

frontend/src/pages/LandingPage.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ import { useNavigate } from 'react-router-dom'
33
import { Navbar, Hero, ResultsView, Features, Pricing, FAQ, Footer } from '@/components/landing'
44
import { API_URL } from '@/config/api'
55
import { playgroundAPI } from '@/services/playground-api'
6-
import { useSmoothScroll } from '@/hooks/useSmoothScroll'
76
import type { SearchResult } from '@/types'
87

98
export function LandingPage() {
109
const navigate = useNavigate()
11-
useSmoothScroll()
1210

1311
const [results, setResults] = useState<SearchResult[]>([])
1412
const [loading, setLoading] = useState(false)

0 commit comments

Comments
 (0)