Skip to content

Commit 853a8ae

Browse files
committed
Merge branch 'main' into add-pacer
2 parents b12ab6b + 224c065 commit 853a8ae

5 files changed

Lines changed: 192 additions & 40 deletions

File tree

app/components/BackgroundAnimation.tsx

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@ export function BackgroundAnimation() {
1919

2020
const canvas = canvasRef.current
2121

22-
const morphDuration = 4000
22+
let morphDuration = 2000
2323
const waitDuration = 1000 * 60 * 2
2424

25-
function easeInOutCubic(t: number, b: number, c: number, d: number) {
26-
if ((t /= d / 2) < 1) return (c / 2) * t * t * t + b
27-
return (c / 2) * ((t -= 2) * t * t + 2) + b
28-
}
25+
const easingFn = cubicBezier(0.645, 0.045, 0.355, 1.0)
2926

3027
if (canvas) {
3128
const ctx = canvas.getContext('2d')!
@@ -67,22 +64,34 @@ export function BackgroundAnimation() {
6764
return array
6865
}
6966

70-
let currentBlobs = createBlobs()
71-
let interBlobs = currentBlobs
67+
let startBlobs = createBlobs()
68+
let currentBlobs = startBlobs
7269
let targetBlobs: ReturnType<typeof createBlobs> = []
7370

71+
function resizeHandler() {
72+
// Create an offscreen canvas and copy the current content
73+
const offscreen = document.createElement('canvas')
74+
offscreen.width = canvas!.width
75+
offscreen.height = canvas!.height
76+
offscreen.getContext('2d')!.drawImage(canvas!, 0, 0)
77+
78+
// Resize the main canvas
79+
canvas!.width = window.innerWidth
80+
canvas!.height = window.innerHeight
81+
82+
// Stretch and redraw the saved content to fill the new size
83+
ctx.drawImage(offscreen, 0, 0, canvas!.width, canvas!.height)
84+
}
85+
7486
function start() {
7587
if (timeout) {
7688
clearTimeout(timeout)
7789
}
7890
if (rafId) {
7991
cancelAnimationFrame(rafId)
8092
}
81-
const parent = canvas!.parentElement
82-
canvas!.width = parent!.clientWidth
83-
canvas!.height = parent!.clientHeight
8493

85-
currentBlobs = interBlobs
94+
startBlobs = JSON.parse(JSON.stringify(currentBlobs))
8695
targetBlobs = createBlobs()
8796
startTime = performance.now()
8897
animate()
@@ -92,45 +101,64 @@ export function BackgroundAnimation() {
92101
ctx.clearRect(0, 0, canvas!.width, canvas!.height)
93102

94103
const time = performance.now() - startTime
95-
const progress = easeInOutCubic(time, 0, 1, morphDuration)
104+
const progress = time / morphDuration
105+
const easedProgress = easingFn(progress)
96106

97107
// Draw the blobs
98-
currentBlobs.forEach((blob, i) => {
108+
startBlobs.forEach((startBlob, i) => {
99109
const targetBlob = targetBlobs[i]
100-
interBlobs[i].x = blob.x + (targetBlob.x - blob.x) * progress
101-
interBlobs[i].y = blob.y + (targetBlob.y - blob.y) * progress
110+
111+
currentBlobs[i].x = interpolate(
112+
startBlob.x,
113+
targetBlob.x,
114+
easedProgress
115+
)
116+
currentBlobs[i].y = interpolate(
117+
startBlob.y,
118+
targetBlob.y,
119+
easedProgress
120+
)
102121

103122
const gradient = ctx.createRadialGradient(
104-
interBlobs[i].x,
105-
interBlobs[i].y,
123+
currentBlobs[i].x,
124+
currentBlobs[i].y,
106125
0,
107-
interBlobs[i].x,
108-
interBlobs[i].y,
109-
interBlobs[i].r
126+
currentBlobs[i].x,
127+
currentBlobs[i].y,
128+
currentBlobs[i].r
110129
)
111130

112-
interBlobs[i].colorH =
113-
blob.colorH + (targetBlob.colorH - blob.colorH) * progress
114-
interBlobs[i].colorS =
115-
blob.colorS + (targetBlob.colorS - blob.colorS) * progress
116-
interBlobs[i].colorL =
117-
blob.colorL + (targetBlob.colorL - blob.colorL) * progress
131+
currentBlobs[i].colorH = interpolate(
132+
startBlob.colorH,
133+
targetBlob.colorH,
134+
easedProgress
135+
)
136+
currentBlobs[i].colorS = interpolate(
137+
startBlob.colorS,
138+
targetBlob.colorS,
139+
easedProgress
140+
)
141+
currentBlobs[i].colorL = interpolate(
142+
startBlob.colorL,
143+
targetBlob.colorL,
144+
easedProgress
145+
)
118146

119147
gradient.addColorStop(
120148
0,
121-
`hsla(${interBlobs[i].colorH}, ${interBlobs[i].colorS}%, ${interBlobs[i].colorL}%, 1)`
149+
`hsla(${currentBlobs[i].colorH}, ${currentBlobs[i].colorS}%, ${currentBlobs[i].colorL}%, 1)`
122150
)
123151
gradient.addColorStop(
124152
1,
125-
`hsla(${interBlobs[i].colorH}, ${interBlobs[i].colorS}%, ${interBlobs[i].colorL}%, 0)`
153+
`hsla(${currentBlobs[i].colorH}, ${currentBlobs[i].colorS}%, ${currentBlobs[i].colorL}%, 0)`
126154
)
127155

128156
ctx.fillStyle = gradient
129157
ctx.beginPath()
130158
ctx.arc(
131-
interBlobs[i].x,
132-
interBlobs[i].y,
133-
interBlobs[i].r,
159+
currentBlobs[i].x,
160+
currentBlobs[i].y,
161+
currentBlobs[i].r,
134162
0,
135163
Math.PI * 2
136164
)
@@ -141,13 +169,15 @@ export function BackgroundAnimation() {
141169
rafId = requestAnimationFrame(animate)
142170
} else {
143171
timeout = setTimeout(() => {
172+
morphDuration = 4000
144173
start()
145174
}, waitDuration)
146175
}
147176
}
148177

178+
resizeHandler()
149179
start()
150-
window.addEventListener('resize', start)
180+
window.addEventListener('resize', resizeHandler)
151181

152182
return () => {
153183
if (rafId) {
@@ -156,7 +186,7 @@ export function BackgroundAnimation() {
156186
if (timeout) {
157187
clearTimeout(timeout)
158188
}
159-
window.removeEventListener('resize', start)
189+
window.removeEventListener('resize', resizeHandler)
160190
}
161191
}
162192
}, [prefersReducedMotion])
@@ -178,3 +208,24 @@ export function BackgroundAnimation() {
178208
</div>
179209
)
180210
}
211+
212+
function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number) {
213+
return function (t: number) {
214+
const cx = 3 * p1x
215+
const bx = 3 * (p2x - p1x) - cx
216+
const ax = 1 - cx - bx
217+
218+
const cy = 3 * p1y
219+
const by = 3 * (p2y - p1y) - cy
220+
const ay = 1 - cy - by
221+
222+
const x = ((ax * t + bx) * t + cx) * t
223+
const y = ((ay * t + by) * t + cy) * t
224+
225+
return y
226+
}
227+
}
228+
229+
function interpolate(start: number, end: number, progress: number) {
230+
return start + (end - start) * progress
231+
}

app/images/neon-dark.svg

Lines changed: 20 additions & 0 deletions
Loading

app/images/neon-light.svg

Lines changed: 25 additions & 0 deletions
Loading

app/utils/partners.tsx

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import sentryWordMarkLightSvg from '~/images/sentry-wordmark-light.svg'
1717
import sentryWordMarkDarkSvg from '~/images/sentry-wordmark-dark.svg'
1818
import speakeasyLightSvg from '~/images/speakeasy-light.svg'
1919
import speakeasyDarkSvg from '~/images/speakeasy-dark.svg'
20+
import neonLightSvg from '~/images/neon-light.svg'
21+
import neonDarkSvg from '~/images/neon-dark.svg'
2022
import { Library } from '~/libraries'
2123

2224
type Partner = {
@@ -31,6 +33,56 @@ type Partner = {
3133
sidebarImgClass?: string
3234
}
3335

36+
const neon = (() => {
37+
const href = 'https://neon.tech?utm_source=tanstack'
38+
39+
return {
40+
name: 'Neon',
41+
id: 'neon',
42+
libraries: ['start', 'router'],
43+
sidebarImgLight: neonLightSvg,
44+
sidebarImgDark: neonDarkSvg,
45+
sidebarImgClass: 'py-3 scale-[1]',
46+
href,
47+
homepageImg: (
48+
<div className="w-full h-full flex items-center justify-center px-4 py-6">
49+
<img
50+
src={neonLightSvg}
51+
alt="Neon"
52+
className="w-[260px] max-w-full dark:hidden"
53+
width="260"
54+
height="72"
55+
/>
56+
<img
57+
src={neonDarkSvg}
58+
alt="Neon"
59+
className="w-[260px] max-w-full hidden dark:block"
60+
width="260"
61+
height="72"
62+
/>
63+
</div>
64+
),
65+
content: (
66+
<>
67+
<div className="text-xs">
68+
Neon and TanStack are joining forces to bring{' '}
69+
<strong>serverless PostgreSQL</strong> to the modern web stack. With
70+
Neon's{' '}
71+
<strong>
72+
blazing-fast branching, autoscaling, and storage/compute separation
73+
</strong>
74+
, developers can instantly spin up production-grade databases for
75+
every branch, test, or feature. TanStack's developer-first framework +
76+
Neon's cutting-edge infra = next-gen DX.
77+
</div>
78+
<span className="text-blue-500 uppercase font-black text-sm">
79+
Learn More
80+
</span>
81+
</>
82+
),
83+
}
84+
})()
85+
3486
const convex = (() => {
3587
const href = 'https://convex.dev?utm_source=tanstack'
3688

@@ -136,15 +188,15 @@ const agGrid = (() => {
136188
<img
137189
src={agGridDarkSvg}
138190
alt="Enterprise Data Grid"
139-
className="w-[270px] max-w-full dark:hidden"
140-
width="270"
191+
className="w-[290px] max-w-full dark:hidden"
192+
width="290"
141193
height="95"
142194
/>
143195
<img
144196
src={agGridLightSvg}
145197
alt="Enterprise Data Grid"
146-
className="w-[270px] max-w-full hidden dark:block"
147-
width="270"
198+
className="w-[290px] max-w-full hidden dark:block"
199+
width="290"
148200
height="95"
149201
/>
150202
</div>
@@ -183,13 +235,13 @@ const netlify = (() => {
183235
sidebarImgDark: netlifyDarkSvg,
184236
sidebarImgClass: 'pt-2 scale-[.9]',
185237
sidebarAfterImg: (
186-
<div className="text-[10px] text-center py-1 px-2 w-full bg-gradient-to-b from-transparent to-gray-500/10 uppercase font-bold">
238+
<div className="text-[10px] rounded-xl m-1 mx-auto w-fit text-center py-px px-2 bg-[#03bdba] text-white uppercase font-bold">
187239
Official Deployment Partner
188240
</div>
189241
),
190242
href,
191243
homepageImg: (
192-
<div className="flex flex-col justify-center items-center pb-4 gap-2 w-full">
244+
<div className="flex flex-col justify-center items-center pb-4 gap-2 relative w-full h-full">
193245
<div className="w-full h-full flex items-center justify-center px-4 pt-6 pb-2">
194246
<img
195247
src={netlifyLightSvg}
@@ -202,7 +254,10 @@ const netlify = (() => {
202254
className="w-[280px] max-w-full hidden dark:block"
203255
/>
204256
</div>
205-
<div className="w-auto text-xs text-center py-1 px-3 rounded-full uppercase font-bold m-2 bg-[#03bdba] text-white ">
257+
<div
258+
className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-[2px] w-auto text-xs text-center
259+
py-1 px-3 rounded-t-xl uppercase font-bold bg-gradient-to-r from-[#03bdba] to-[#00aaba] text-white "
260+
>
206261
Official Deployment Partner
207262
</div>
208263
</div>
@@ -469,6 +524,7 @@ export const partners: Partner[] = [
469524
clerk,
470525
agGrid,
471526
netlify,
527+
neon,
472528
convex,
473529
sentry,
474530
speakeasy,

media/brand.sketch

-91.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)