60fps/ui
A collection of headless interaction engines — carousel, drag, motion and scroll-reveal — written once in framework-agnostic TypeScript, then wrapped in thin, idiomatic adapters for React and Vue.
The engine owns the behaviour (DOM measurement, event listeners, data-* attributes, an event
emitter); the adapter owns the lifecycle and reactivity for your framework. Swap the adapter, keep
the engine.
The two layers
Every primitive is split the same way:
| Layer | What it does | Example |
|---|---|---|
| Engine | Vanilla class extending an Emitter, with init(el) / clean(). No framework imports. |
new CarouselEngine() |
| Adapter | A hook/composable that instantiates the engine, drives init/clean, and mirrors state. |
useCarousel(ref) |
This means the hard part — the interaction logic — has a single implementation and a single test suite, while each framework gets an API that feels native to it.
Packages
| Package | Contents |
|---|---|
@60fps/ui-utils |
Shared primitives: Emitter, DOM helpers, math, ResizeObserver / IntersectionObserver managers |
@60fps/ui-motion |
Motion — animate a value with spring, damping or inertia |
@60fps/ui-drag |
DragEngine — pointer & touch drag gestures |
@60fps/ui-carousel |
CarouselEngine — accessible scroll-snap carousel |
@60fps/ui-inview |
InViewEngine + portable CSS — reveal on viewport entry |
@60fps/ui-video |
VideoEngine + PosterVideoEngine — polite playback & lazy poster→video |
@60fps/ui-react |
React hooks for every engine (@60fps/ui-react/carousel-engine, …) |
@60fps/ui-vue |
Vue composables for every engine (@60fps/ui-vue/carousel-engine, …) |
Install
# React
pnpm add @60fps/ui-react @60fps/ui-motion @60fps/ui-drag @60fps/ui-carousel @60fps/ui-inview @60fps/ui-video
# Vue
pnpm add @60fps/ui-vue @60fps/ui-motion @60fps/ui-drag @60fps/ui-carousel @60fps/ui-inview @60fps/ui-video
Head to Motion to see the pattern in action, or jump straight to Carousel and InView.