back to lab
Neobrutalist button
The site's press-down button pattern, rebuilt from scratch: shadow sinks, border stays, gsap wiggles the icon.
preview
function Sketch() { const ref = useRef(null) const [count, setCount] = useState(0) useEffect(() => { if (count === 0) return const ctx = gsap.context(() => { gsap.fromTo( ".star", { rotation: -20, scale: 0.6 }, { rotation: 0, scale: 1, ease: EASE.jelly, duration: 0.8 } ) }, ref) return () => ctx.revert() }, [count]) return ( <div ref={ref} className="flex h-full min-h-56 flex-col items-center justify-center gap-5"> <button type="button" onClick={() => setCount((c) => c + 1)} className="flex items-center gap-2 rounded-sm border-2 border-border bg-accent-cyan px-5 py-2.5 font-nav text-sm font-bold text-fixed-dark shadow-hard transition-all hover:shadow-hard-sm hover:translate-x-[1px] hover:translate-y-[1px] active:translate-x-[2px] active:translate-y-[2px] active:shadow-none" > <span className="star inline-flex"> <Star size={16} strokeWidth={2.5} /> </span> press me </button> <p className="font-mono text-xs uppercase tracking-wider text-ink-muted"> pressed {count}x </p> </div> ) } render(<Sketch />)
what's in scope
Sketches run with these values already available — no imports needed. Anything Tailwind can style, gsap can move.
- react
- React
- useState
- useEffect
- useRef
- useMemo
- useCallback
- useLayoutEffect
- motion
- gsap
- EASE
- DURATION
- STAGGER
- utils
- cn
- icons
- ArrowRight
- Check
- Heart
- Moon
- Sparkles
- Star
- Sun
- Zap