@react-kino/core
v0.3.0
Published
Framework-agnostic scroll engine powering react-kino
Downloads
1,243
Readme
Do you need this package?
Probably not directly. @react-kino/core is the low-level scroll math (progress calculation, easing, duration parsing, pinning checks) that react-kino wraps with React components and hooks. If you're building with React, install react-kino instead -- it re-exports the types from this package (EasingName, EasingFn, ProgressData) so you rarely need to depend on @react-kino/core yourself.
Install this package directly only if you're integrating the scroll engine into a non-React app, or building bindings for another framework.
npm install @react-kino/coreWhat's included
ScrollTracker-- subscribes towindowscroll/resize events, batches updates viarequestAnimationFrame, and emits{ scrollY, viewportHeight, scrollHeight, progress }to subscribers. Resize bursts (window drags, mobile browser URL-bar show/hide) are debounced and coalesced into a single rAF-scheduled emission so viewport-dependent values stay in sync.ProgressValue-- a tiny, React-free "motion value". Holds a single number, notifies subscribers imperatively on change (get()/set(n)/on(fn)), and skips redundant notifications when the value is unchanged. This is the backbone of react-kino's ref-based rendering engine: components subscribe and write to the DOM directly, bypassing React's render cycle on the scroll hot path.calcElementProgress(offsets, info)-- computes element-relative scroll progress (0-1) from Motion-style offset pairs like["start end", "end start"], mapping an element's viewport entry/exit without pinning. Pure and unit-tested; helpersedgeToFraction,parseOffsetEntry, andresolveOffsetScrollYare also exported.calcSceneProgress(scrollY, offsetTop, duration)-- computes a pinned scene's progress (0-1) from raw scroll position.parseDuration(duration, viewportHeight)-- parses a CSS-like duration string ("200vh","1500px") into pixels. Warns in development (not production) and falls back to0if the input can't be parsed.isSceneActive(scrollY, offsetTop, duration)-- returns whether a scene is currently within its scroll range.clamp(value, min, max)/lerp(a, b, t)-- small numeric helpers used throughout the engine.- Easing presets --
linear,easeIn,easeOut,easeInOut,easeInCubic,easeOutCubic,easeInOutCubic,easeInQuart,easeOutQuart,easeInOutQuart, plus anEASINGSlookup keyed by the typedEasingNameunion ("linear" | "ease-in" | "ease-out" | "ease-in-out" | "ease-in-cubic" | "ease-out-cubic" | "ease-in-out-cubic" | "ease-in-quart" | "ease-out-quart" | "ease-in-out-quart"). - Types --
EasingFn,EasingName,SceneConfig,ProgressData,ScrollSubscriber,ProgressListener,OffsetEdge,OffsetEntry,ElementOffsetInfo.
import { ProgressValue, calcElementProgress } from "@react-kino/core";
// A motion value you can write to without re-rendering anything.
const progress = new ProgressValue(0);
const unsubscribe = progress.on((p) => {
element.style.setProperty("--kino-progress", String(p));
});
progress.set(0.5); // notifies subscribers; set(0.5) again is a no-op
// Element-relative progress (0 as it enters, 1 once it has fully passed).
const p = calcElementProgress(["start end", "end start"], {
elementTop: 1200, // rect.top + scrollY
elementHeight: 480,
viewportHeight: 800,
scrollY: 900,
});import { ScrollTracker, calcSceneProgress, parseDuration } from "@react-kino/core";
const tracker = new ScrollTracker();
const unsubscribe = tracker.subscribe(({ scrollY, viewportHeight }) => {
const durationPx = parseDuration("300vh", viewportHeight);
const progress = calcSceneProgress(scrollY, /* offsetTop */ 0, durationPx);
console.log(progress); // 0 -> 1
});
tracker.start();
// later: unsubscribe(); tracker.stop();Design goals
- Zero dependencies -- pure TypeScript, runs anywhere (browser, edge runtimes) with no Node.js assumptions.
- Framework-agnostic -- no React (or any UI framework) in this package;
react-kinois the React binding. - Tiny -- the entire engine is under 1 KB gzipped.
- Type-safe -- ships full
.d.tsdeclarations and source maps.
License
MIT
