mirror of
https://github.com/System-End/site.git
synced 2026-04-19 16:28:21 +00:00
251 lines
12 KiB
JavaScript
251 lines
12 KiB
JavaScript
import { useEffect, useRef } from 'react'
|
|
import usePrefersReducedMotion from '../../lib/use-prefers-reduced-motion'
|
|
import { Box, Grid } from 'theme-ui'
|
|
import sleep from '../../lib/sleep'
|
|
|
|
const dimBg = '#151515'
|
|
|
|
// "LET'S RECAP" pixel art (exported from Piskel)
|
|
// Original: https://doggo.ninja/fiK0nk.piskel
|
|
const recapWidth = 71
|
|
const recapHeight = 10
|
|
const recapPixels = [
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
|
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
|
|
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000,
|
|
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0xffffffff, 0xffffffff
|
|
]
|
|
|
|
const Recap = () => {
|
|
const prefersReducedMotion = usePrefersReducedMotion()
|
|
// Fancy lights animation
|
|
const lightsScrollTrigger = useRef()
|
|
const lightsAnimated = useRef(false)
|
|
useEffect(() => {
|
|
let canceled = false
|
|
|
|
const setAtIndex = (i, color) => {
|
|
if (canceled) return
|
|
|
|
// Going outside of React for performance
|
|
const el = document.getElementById(`pixel-${i}`)
|
|
if (!el) return
|
|
|
|
if (recapPixels[i]) {
|
|
el.style.background = color
|
|
el.style.boxShadow = `0 0 10px ${color}`
|
|
} else {
|
|
el.style.background = dimBg
|
|
el.style.boxShadow = 'none'
|
|
}
|
|
}
|
|
const setAll = color => {
|
|
for (let i = 0; i < recapPixels.length; i++) setAtIndex(i, color)
|
|
}
|
|
|
|
const animate = async () => {
|
|
if (lightsAnimated.current) return
|
|
lightsAnimated.current = true
|
|
|
|
// Illuminate lights in diagonal lines starting with only top left.
|
|
for (
|
|
let curColumn = 0;
|
|
curColumn < recapWidth + recapHeight;
|
|
curColumn++
|
|
) {
|
|
for (
|
|
let offset = curColumn;
|
|
offset >= Math.max(0, curColumn - recapHeight);
|
|
offset--
|
|
) {
|
|
const i = curColumn * recapWidth + offset - offset * recapWidth
|
|
setAtIndex(i, '#ffffff')
|
|
if (!recapPixels[i]) await sleep(4)
|
|
if (canceled) return
|
|
}
|
|
// await sleep(2); if (canceled) return
|
|
}
|
|
|
|
// Flash the lights twice
|
|
await sleep(600)
|
|
if (canceled) return
|
|
|
|
setAll(dimBg)
|
|
await sleep(80)
|
|
if (canceled) return
|
|
|
|
setAll('#aaaaaa')
|
|
await sleep(20)
|
|
if (canceled) return
|
|
|
|
setAll(dimBg)
|
|
await sleep(30)
|
|
if (canceled) return
|
|
|
|
setAll('#aaaaaa')
|
|
await sleep(100)
|
|
if (canceled) return
|
|
|
|
setAll(dimBg)
|
|
await sleep(200)
|
|
if (canceled) return
|
|
|
|
// Animate rainbow 2-column increments
|
|
for (let x = 0; x < recapWidth; x++) {
|
|
const color = `hsl(${(x * 360) / recapWidth}, 100%, 65%)`
|
|
for (let y = 0; y < recapHeight; y++) {
|
|
const i = y * recapWidth + x
|
|
setAtIndex(i, color)
|
|
}
|
|
if (x % 2 === 1) await sleep(35)
|
|
}
|
|
}
|
|
|
|
if (prefersReducedMotion) {
|
|
if (!lightsAnimated.current) setAll('#ffffff')
|
|
return () => (canceled = true)
|
|
} else {
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) animate()
|
|
},
|
|
{ threshold: 0.5 }
|
|
)
|
|
observer.observe(lightsScrollTrigger.current)
|
|
return () => {
|
|
canceled = true
|
|
observer.disconnect()
|
|
}
|
|
}
|
|
}, [prefersReducedMotion])
|
|
|
|
return (
|
|
<Grid
|
|
ref={lightsScrollTrigger}
|
|
gap={['2px', '3px', '4px']}
|
|
columns={recapWidth}
|
|
sx={{ width: '100%', maxWidth: 800 }}
|
|
>
|
|
{recapPixels.map((_, i) => (
|
|
<Box id={`pixel-${i}`} key={i} sx={{ bg: dimBg, paddingTop: '100%' }} />
|
|
))}
|
|
</Grid>
|
|
)
|
|
}
|
|
|
|
export default Recap
|