@linear_non/stellar-libs
v1.6.13
Published
Reusable JavaScript libraries for Non-Linear Studio projects.
Readme
stellar-libs
@linear_non/stellar-libs— Reusable UI behavior modules for Non-Linear Studio projects.
A collection of lightweight, self-contained frontend UI behavior modules built to work seamlessly with @linear_non/stellar-kit. Each library provides specific functionality and can be dropped into modular websites with minimal configuration.
Available Libraries
| Library | Description | |---|---| | Sticky | Sticky scroll behavior with GSAP ScrollTrigger | | Smooth | Smooth scroll system using VirtualScroll | | SplitOnScroll | Text splitting with scroll-triggered reveals | | Noise | Canvas-based animated noise effect | | SpritePlayer | Image sequence player on canvas | | CursorTracker | Custom cursor that follows mouse | | Marquee | Infinite horizontal marquee scroller | | Slider | Drag slider with optional infinite loop and progress | | ScrollTo | Declarative click-to-scroll via data attributes |
Installation
npm install @linear_non/stellar-libs
npm install @linear_non/stellar-kitLocal Development
npm install
npm run devLaunches a Vite dev server with a demo index linking to individual playgrounds for each library.
Symlink into a project
To test local changes in a real project (e.g. nonlinear-v2) without publishing:
# 1. Create a global link from stellar-core
cd stellar-core/packages/libs
pnpm link --global
# 2. Consume the link in your project
cd your-project
pnpm link --global @linear_non/stellar-libs
# 3. Unlink when done (restores the npm version)
cd your-project
pnpm unlink @linear_non/stellar-libs
pnpm installUsage
Sticky
import { Sticky } from "@linear_non/stellar-libs"
const sticky = new Sticky({
el: document.querySelector(".sticky-container"),
sticky: document.querySelector(".sticky-element"),
isSmooth: false,
onUpdateCallback: ({ progress }) => console.log(progress),
})In non-smooth mode, Sticky uses native CSS
position: sticky— no-fixedclass needed. In smooth mode, ScrollTrigger handles positioning via transforms.
Smooth
import { Smooth } from "@linear_non/stellar-libs"
const smooth = new Smooth({ scroll: kitStore.scroll })<section data-smooth data-speed="0.8">Parallax content</section>SplitOnScroll
import { SplitOnScroll } from "@linear_non/stellar-libs"
const split = new SplitOnScroll({
el: document.querySelector(".trigger"),
splitText: document.querySelectorAll("h1"),
isReady: ({ splits, groups }) => {
gsap.from(splits[0].chars, { y: 40, opacity: 0, stagger: 0.03 })
},
once: true,
})The constructor key is
splitText(notsplitTargets). TheisReadycallback receives{ splits, groups }.
Noise
import { Noise } from "@linear_non/stellar-libs"
const noise = new Noise({
target: ".noise-canvas",
density: 0.75,
color: 0xf3f2feff,
opacity: 0.25,
fps: 24,
})SpritePlayer
import { SpritePlayer } from "@linear_non/stellar-libs"
const player = new SpritePlayer({
canvas: document.querySelector("canvas"),
container: document.querySelector(".player-container"),
desktop_path: "/sprites/desktop/",
mobile_path: "/sprites/mobile/",
fileName: "frame_",
total: 60,
priorityFrames: 30, // load first 30 frames, rest in background (default: min(30, total))
})
// init() is called automatically by the constructor
// listen for sprite:ready (phase 1 done) or sprite:loaded (all frames done)
player.setProgress(0.5)CursorTracker
import { CursorTracker } from "@linear_non/stellar-libs"
const tracker = new CursorTracker({
container: document.querySelector(".hover-area"),
el: document.querySelector(".cursor"),
ease: 0.12,
isCentered: true,
})
// Custom hover animation (optional — defaults to autoAlpha fade)
const tracker = new CursorTracker({
container: document.querySelector(".hover-area"),
el: document.querySelector(".cursor"),
animation: {
in: (el) => gsap.to(el, { autoAlpha: 1, scale: 1, duration: 0.4, ease: "back.out" }),
out: (el) => gsap.to(el, { autoAlpha: 0, scale: 0.5, duration: 0.3 }),
},
})
CursorTrackersubscribes toAPP_TICKinternally — do not add an external tick subscription.
Marquee
import { Marquee } from "@linear_non/stellar-libs"
const marquee = new Marquee({
container: document.querySelector(".marquee"),
el: document.querySelector(".marquee__track"),
speed: 50,
gap: "1.6rem",
})Slider
import { Slider } from "@linear_non/stellar-libs"
const slider = new Slider({
container: document.querySelector(".slider"),
el: document.querySelector(".slider__track"),
speed: 0.1,
snap: true,
infinite: false,
activeBelow: 'mediumUp', // only active below the mediumUp breakpoint; mobileOnly:true is an alias
prevEl: document.querySelector(".prev"),
nextEl: document.querySelector(".next"),
progressEl: document.querySelector(".progress-fill"),
onSlideChange: ({ index, total }) => console.log(index, total),
momentumTouch: 0.35, // free-mode (snap:false) coast factor for touch
momentumMouse: 0.55, // free-mode coast factor for mouse/trackpad
axisThreshold: 6, // px before gesture commits to X or Y axis
})<div class="slider">
<div class="slider__track">
<div class="slide">01</div>
<div class="slide">02</div>
<div class="slide">03</div>
</div>
</div>Prev/next buttons auto-disable with
-disabledclass +aria-disabledat start/end (non-infinite only). Style with.prev.-disabled, .next.-disabled { opacity: 0.3; pointer-events: none; }. Progress bar accounts for visible slides — starts atslidesInView / total, reaches exactlyscaleX(1)at the last position. Touch gets 1:1 drag + iOS-style settle; mouse/trackpad keeps damp-based lerp. Setsnap: falsefor free-scroll with momentum.
ScrollTo
import { ScrollTo } from "@linear_non/stellar-libs"
const scrollTo = new ScrollTo({ scope: document })
// On page destroy:
scrollTo.destroy()<a href="#about" data-scroll-to>About</a>
<button data-scroll-to="top">Back to top</button>
<button data-scroll-to=".contact" data-scroll-to-offset="-80" data-scroll-to-duration="2">Contact</button>Uses
Application.scrollTo()under the hood — works with both internal smooth scroll and Lenis.
Roadmap
- [ ] TypeScript definitions (
.d.tsfor all 8 libraries) - [ ] Unit test suite (per-library Jest tests)
- [ ] Accessibility — ARIA attributes + keyboard support (Slider, Marquee, CursorTracker)
- [ ] Animation presets — exportable GSAP timeline builders per library
- [ ] Performance monitoring — FPS tracking integrated with stellar-kit
?debug - [ ] Storybook interactive docs
- [ ] Plugin system —
.use(plugin)extension API
Lifecycle
All libraries follow a consistent class-based lifecycle: init() → on() → tick() → resize() → off() → destroy()
Always call destroy() on page navigation to clean up event listeners, animations, and timers.
Made with ❤️ by Non-Linear Studio
