Morphiq

Components / Elastic Rail

Elastic Rail

A scroll progress rail that bows when you push past the end of the page — with a wheel, a finger or the arrow keys, on every platform, not only where the browser rubber-bands — and twangs back when you let go. It is a string fixed at both ends obeying the wave equation, so its pitch is not a constant somebody picked: f = (1/2L)·√(T/μ), which means a longer rail rings lower on its own. Nothing is tuned per page — the geometry does it.

Usage

import ElasticRail from '@/components/elastic-rail'

<ElasticRail tension={5200} damping={4.5} />

Installation

npx shadcn@latest add https://morphiq.prathampatel.design/r/elastic-rail.json

Model

f = (1/2L)·√(T/μ)

L the rail’s own length · T tension · μ 8.3×10⁻⁴ per px · a push of x px past the end stands in for overscroll as 0.55·x·R/(R + 0.55·x), R the reach

Props

PropertyTypeDefaultDescription
nodesnumber24Simulation nodes along the string, 4 to 256. Default 24.
tensionnumber5200String tension T. Wave speed is √(T/μ) with μ = 8.3×10⁻⁴ per px, and the pitch follows from that and the rail's own length: f = (1/2L)·√(T/μ). Default 5200.
dampingnumber4.5How quickly the ring dies, 1/s: its amplitude falls as e^(−damping·t/2). Default 4.5.
givenumber0.42Px of bulge per px of overscroll. Negative bows it the other way. Default 0.42.
reachnumber120The most overscroll, px, the rail stands in for on platforms that have none of their own: a wheel, a finger or a scroll key pushing past the end is resisted like a rubber-banding page and never comes to more than this. 0 leaves only the platform's own elastic overscroll. Default 120.
thicknessnumber3Stroke width, px. Default 3.
progressColorstring—Colour of the fill. currentColor when unset.
trackColorstring—Colour of the track, drawn at 18% opacity. currentColor when unset.
verticalbooleanfalseRun top to bottom rather than left to right. Default false.
targetHTMLElement | null—Element to track. Defaults to the page.