Core Guide

The @reelkit/core package provides the framework-agnostic slider logic. Use it to build custom integrations or understand the underlying architecture.

Architecture Overview

The core uses a controller pattern with factory functions. No classes — all plain objects returned from closures. Zero dependencies. The core coordinates:

  • SliderController — central state management and navigation
  • GestureController — touch/pointer drag handling
  • KeyboardController — arrow keys and Escape
  • WheelController — mouse wheel with debounce

createSliderController

Creates a new slider controller instance that manages all slider state and behavior.

typescript

Controller Methods

typescript

Lifecycle

typescript

State Updates

typescript

Virtualization

The core renders only 3 slides to DOM at any time (current, previous, next). The range extractor determines which indices are included in the rendered window:

typescript
The result is always clamped to a maximum of 3 indices. If your extractor returns more, the core keeps 3 centered around the current slide.

Signals

The core uses a lightweight signal system for reactivity:

typescript

Controller State

Access reactive state through controller.state:

typescript

Timeline Controller

Build a custom scrub bar for any <video> element. The controller exposes reactive signals for duration, current time, buffered ranges, and scrubbing state, and wires pointer plus keyboard interactions onto any DOM element in one call.

typescript

URL State

Put an overlay’s open state in the address bar: the visible slide gets a link that can be shared, deep-linked, and closed with the back button. The core owns the model; the bindings wrap it in a hook (React/Vue useOverlayUrlState, Angular createOverlayUrlState) and a URL-driven overlay component.

How it works

createUrlStateController mirrors one query parameter into a signal and writes changes back. Opening pushes one history entry; every navigation replaces it — a hundred swipes add none, so one back step always closes. A UrlAdapter is the pluggable read/write seam: the default drives history.pushState, and a routed app passes a router-backed adapter so the router’s own location never goes stale.

typescript

Codec and locator — two jobs

A key is a matched { codec, locator } pair. Spelling an identity into the URL and finding where it currently sits are separate concerns, so they are separate objects:

  • codec — the wire. encode spells an identity into the parameter text; decode parses it back, and rejects a malformed value so the parameter self-heals out of the URL.
  • locator — the lookup. locate finds where a decoded identity sits in the live collection (or null if it is gone); identify reads a position back to its identity for writes; optional locateAsync pages a windowed or infinite feed on a miss.

Keeping them separate lets you pair any wire with any lookup — a stable id codec with a paging locator, for instance.

Index vs stable-id keys

Two built-in keys build that pair for you; they differ only in what the URL names:

  • urlIndexKey(() => count) addresses by position (?photo=3). Simplest, but a bookmark opens a different item once the list is reordered.
  • urlStableIdKey({ items }) addresses by each item’s stable id (?photo=post_42), scanning the live list — the bookmark still names that item after a reorder, or drops cleanly when it is gone. hashCodec: base64UrlCodec base64url-obscures the id (reversible, not a cryptographic hash).

Paging a windowed feed? Both built-in keys take an optional locateAsync urlIndexKey(() => count, locateAsync) and urlStableIdKey({ items, locateAsync }). The synchronous lookup answers for what has loaded; a miss pages the rest in, so a shared link past the window still opens — no hand-rolled codec or locator.

Two axes? urlIndexTwoAxisKey carries ?p=<outer>.<inner> for a post plus an inner media index. Full options live on the Core API reference.

Next Steps