Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(suspensive.org): beautify main page by star animation #1398

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 34 additions & 34 deletions docs/suspensive.org/public/img/homepage_background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 141 additions & 1 deletion docs/suspensive.org/src/components/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { motion } from 'motion/react'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'nextra/hooks'
import { useEffect, useRef } from 'react'

const CodeBlockClassName = 'nextra-code'

Expand Down Expand Up @@ -33,8 +34,9 @@ export const HomePage = ({
<motion.section
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="bg-[url('/img/homepage_background.svg')] bg-cover bg-center bg-no-repeat pb-20"
className="relative bg-[url('/img/homepage_background.svg')] bg-cover bg-center bg-no-repeat pb-20"
>
<StarCanvas />
<div className="flex flex-col items-center justify-center gap-8 text-center">
<div className="flex flex-col items-center">
<Image
Expand Down Expand Up @@ -106,3 +108,141 @@ export const HomePage = ({
</>
)
}

interface Vertex {
pos: number[]
velocity: number[]
distance: number
size: number
}

const tile = 80
manudeli marked this conversation as resolved.
Show resolved Hide resolved
const OFFSET_FACTOR = 0.75
const RANDOM_Z_FACTOR = 1
const VELOCITY_CONSTANT = 8
const RANDOM_DISTANCE_MAX = 900
const RANDOM_SIZE_FACTOR = 2

const StarCanvas = () => {
const animationFrameIdRef = useRef<number | null>(null)
const resizeAnimationFrameIdRef = useRef(0)
const onRenderRef = useRef<VoidFunction | null>(null)
const canvasRef = useRef<HTMLCanvasElement>(null)

useEffect(() => {
const canvas = canvasRef.current
const parentElement = canvas?.parentElement
const ctx = canvas?.getContext('2d')
const vertexMap: Record<string, Vertex> = {}
const startTime = Date.now()

function onResize() {
const inlineSize = parentElement?.offsetWidth ?? 0
const blockSize = parentElement?.offsetHeight ?? 0

cancelAnimationFrame(resizeAnimationFrameIdRef.current)
resizeAnimationFrameIdRef.current = requestAnimationFrame(() => {
if (canvas) {
canvas.width = inlineSize
canvas.height = blockSize
canvas.style.cssText += `width: ${inlineSize}px; height: ${blockSize}px;`
onRenderRef.current?.()
}
})
}

function getVertex(sx: number, sy: number): Vertex {
const id = `${sx}x${sy}`

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!vertexMap[id]) {
const x = tile * sx + tile * 1.5 * Math.random() - tile * OFFSET_FACTOR
const y = tile * sy + tile * 1.5 * Math.random() - tile * OFFSET_FACTOR
const z = Math.random() * RANDOM_Z_FACTOR
const vx = 1 + Math.random() * VELOCITY_CONSTANT
const vy = 1 + Math.random() * VELOCITY_CONSTANT
const distance = 10 + Math.random() * RANDOM_DISTANCE_MAX
const size = 0.1 + Math.random() * RANDOM_SIZE_FACTOR

vertexMap[id] = {
pos: [x, y, z],
velocity: [vx, vy],
size,
distance,
}
}
return vertexMap[id]
}

function onRender() {
const width = canvas?.width ?? 0
const height = canvas?.height ?? 0
const distTime = Date.now() - startTime

ctx?.clearRect(0, 0, width, height)

const maxSX = Math.ceil(width / tile)
const maxSY = Math.ceil(height / tile)

for (let sx = 0; sx <= maxSX; ++sx) {
for (let sy = 0; sy <= maxSY; ++sy) {
const { velocity, distance, pos, size } = getVertex(sx, sy)
const scalar = Math.sqrt(
velocity[0] * velocity[0] + velocity[1] * velocity[1]
)
const totalDistance = (distTime * scalar) / 1000
const isReverse = Math.floor(totalDistance / distance) % 2 !== 0
let nextDistance = totalDistance % distance

if (isReverse) {
nextDistance = distance - nextDistance
}
const x = pos[0] + (nextDistance / scalar) * velocity[0]
const y = pos[1] + (nextDistance / scalar) * velocity[1]
const a = 1 - pos[2]

ctx?.beginPath()
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
ctx!.fillStyle = `rgba(255, 255, 255, ${a})`
ctx?.arc(x, y, size, 0, 2 * Math.PI)
ctx?.fill()
}
}
}

onRenderRef.current = onRender
const observer = new ResizeObserver(onResize)
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
parentElement && observer.observe(parentElement)

return () => {
cancelAnimationFrame(resizeAnimationFrameIdRef.current)
observer.disconnect()
}
}, [])

useEffect(() => {
const requestAnimation = () => {
onRenderRef.current?.()
animationFrameIdRef.current = requestAnimationFrame(requestAnimation)
}

if (animationFrameIdRef.current === null) {
animationFrameIdRef.current = requestAnimationFrame(requestAnimation)
}

return () => {
if (animationFrameIdRef.current !== null) {
cancelAnimationFrame(animationFrameIdRef.current)
animationFrameIdRef.current = null
}
}
}, [])

return (
<canvas
ref={canvasRef}
className="absolute bottom-0 left-0 right-0 top-0 -z-10 opacity-30"
/>
)
}
2 changes: 1 addition & 1 deletion docs/suspensive.org/src/components/SectionText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export const SectionTitle = ({ children }: { children: ReactNode }) => (
</h3>
)
export const SectionDescription = ({ children }: { children: ReactNode }) => (
<h4 className="text-center text-4xl font-bold">{children}</h4>
<h4 className="text-center text-3xl font-bold md:text-4xl">{children}</h4>
)
2 changes: 1 addition & 1 deletion docs/suspensive.org/src/pages/en/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ const Page = () => (

</Scrollycoding>

<SectionDescription>ErrorBoundaryGroup, ErrorBoundary</SectionDescription>
<SectionDescription>ErrorBoundary, ErrorBoundaryGroup</SectionDescription>
<br />

<Scrollycoding>
Expand Down
2 changes: 1 addition & 1 deletion docs/suspensive.org/src/pages/ko/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ const Page = () => (

</Scrollycoding>

<SectionDescription>ErrorBoundaryGroup, ErrorBoundary</SectionDescription>
<SectionDescription>ErrorBoundary, ErrorBoundaryGroup</SectionDescription>
<br />

<Scrollycoding>
Expand Down
Loading