npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@samline/ticker

v2.2.0

Published

An accessible, dependency-free ticker (marquee) for vanilla JavaScript, TypeScript, and plain HTML.

Readme

@samline/ticker

An accessible, dependency-free ticker for JavaScript, TypeScript and plain HTML. Enhance existing markup with an owned controller or initialize declarative tickers at page level.

Demo · Examples · Documentation · Changelog

Table of contents

Installation

npm install @samline/ticker
pnpm add @samline/ticker
bun add @samline/ticker

Requires Node 20+ when bundling. Runtime target is ES2020.

Import the stylesheet once in your application entrypoint:

import '@samline/ticker/style.css'

Quick start

<div id="news-ticker">
  <a href="/one">First story</a>
  <a href="/two">Second story</a>
</div>
import { ticker } from '@samline/ticker'
import '@samline/ticker/style.css'

const news = ticker('#news-ticker', {
  duration: 20,
  direction: 'left',
  pauseOnHover: true,
})

news?.update({ duration: 30 })
news?.refresh()
news?.destroy()

What this does:

  • Enhances the existing element and returns an element-scoped controller.
  • Measures its content and creates enough visual clones to fill the viewport.
  • Preserves fractional widths and horizontal gaps so repeated content aligns at each loop reset.
  • Hides repeated content from assistive technology and keyboard navigation by default.
  • Reuses visual clones when responsive measurements are unchanged and pauses animation outside the viewport or while the document is hidden.
  • Restores the original source element when destroy() runs.

Seamless loops

The runtime preserves fractional measurements in both directions. Match item spacing to the horizontal track gap and include any decorative separator at the end of the sequence. See Styling: seamless loops for the CSS pattern.

HTML / CDN

Choose Package / ESM when installing with npm, pnpm or bun and importing Ticker in your application. Choose HTML / CDN when loading the standalone script in plain HTML, WordPress or Shopify without a bundler. Both use the same controller API. A CDN only delivers the files; you can self-host the same script and stylesheet.

<link rel="stylesheet" href="https://unpkg.com/@samline/[email protected]/dist/style.css" />
<script src="https://unpkg.com/@samline/[email protected]/dist/browser/global.global.js"></script>

Pin the version in production. Replace 2.2.0 with the version you ship.

The standalone script (an IIFE) exposes window.Ticker. “Global” describes this object, not another loading mode. The optional @samline/ticker/browser registry module is an ESM/CJS import and does not install that object. See loading terms.

<div id="news"><a href="/news">Latest story</a></div>

<script>
  const news = window.Ticker.ticker('#news', {
    duration: 24,
    pauseOnHover: true,
  })

  news?.update({ duration: 30 })
</script>

For optional ID-based ownership, window.Ticker.newTicker({ id, options }) creates a registry entry; destroyTicker(id) removes it. A direct ticker() controller is unregistered and uses its own destroy(). See Registry reference for the complete browser API.

Capabilities

  • News, announcement, logo, sponsor, and promotion tickers.
  • Progressive enhancement for server-rendered or CMS-owned markup.
  • Responsive marquees that remeasure after fonts, layout, or content change.
  • Browser-global integrations for WordPress, Shopify, and plain HTML.
  • Declarative tickers that are discovered as the DOM changes.

API at a glance

| Group | API | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Controller factory | ticker() | | Controller lifecycle | update() · refresh() · destroy() | | Declarative lifecycle | mount() · refresh() · unmount() | | Browser registry | newTicker() and registry helpers | | Configuration | TickerOptions | | Core utilities | Defaults, state factories, and validators | | Types | TypeScript reference |

The controller exposes element, source, state, and an immutable options snapshot. Playback, navigation, events and viewport rules are documented in the controller reference. update() and instance refresh() are chainable; destroy() owns teardown and restoration.

See the complete API reference.

Entrypoints

| Entrypoint | When to use | | -------------------------------- | ------------------------------------------------------------- | | @samline/ticker | Main API, browser singleton, types, defaults, and validators. | | @samline/ticker/vanilla | ticker() plus declarative page lifecycle helpers. | | @samline/ticker/browser | ESM/CJS browser registry without a global side effect. | | @samline/ticker/browser/global | Pre-bundled IIFE that installs window.Ticker. | | @samline/ticker/core | Types, defaults, state factories, and validation helpers. | | @samline/ticker/style.css | Required layout, animation, and reduced-motion styles. |

The main entrypoint also exports browser, the same registry singleton used by the browser module, without installing window.Ticker. See Browser integration.

Playback, navigation and responsive motion

const news = ticker('#news', {
  speed: 40, // CSS pixels per second; takes precedence over duration.
  direction: 'auto', // Inherited LTR moves left; inherited RTL moves right.
  autoplay: false,
  navigation: true,
  responsive: [{ query: '(width < 48rem)', options: { speed: 24 } }],
})
news?.play()
news?.pause()
news?.scrollBy(120) // Instant logical distance; wraps and leaves playback paused.
const unsubscribe = news?.on('playback', state => console.log(state.playing, state.reasons))

direction also accepts physical left/right and vertical up/down. Give vertical wrappers an explicit height. pauseOnFocus defaults to true; manual pause survives environmental and breakpoint changes. play() respects reduced motion, document visibility and viewport intersection. Attach application-owned native buttons and a labelled range using connectControls({ previous, next, rail }); navigation: true enables touch/mouse dragging without blocking perpendicular page scroll. Set resumeAfterDrag: true to restore prior playback intent on release; a manual pause remains paused and hover/focus pauses still apply. Responsive rules use viewport media queries in array order over the current base configuration. The same typed controller is returned by Package / ESM and HTML / CDN factories, with equivalent declarative data attributes. Compare enabled/disabled resumption in the drag example; its control calls update({ resumeAfterDrag }) without changing playback intent.

Content stays application-owned: add or remove original nodes through source, then call refresh(). Use speed to keep a dynamic feed steady as it grows or shrinks; an empty feed can be repopulated and refreshed.

See configuration for normalization, RTL and rule precedence, and controller contracts for events, keyboard controls and cleanup.

Smooth arrow steps

Create native #previous and #next buttons beside the Quick start source. This is an alternative setup; do not initialize that source twice.

import { ticker } from '@samline/ticker'
import '@samline/ticker/style.css'

const strip = ticker('#news-ticker', { navigation: true, autoplay: true })
const disconnect = strip?.connectControls({
  previous: document.querySelector<HTMLButtonElement>('#previous')!,
  next: document.querySelector<HTMLButtonElement>('#next')!,
  behavior: 'smooth',
  duration: 300,
  preservePlayback: true,
})

Use your existing controller instead of resuming on every navigate event. preservePlayback retains manual pause as well as autoplay. Instant navigation that pauses playback remains the default. Reduced motion always seeks instantly. See the controller documentation for cancellation and navigationSource events.

Documentation

Read the full guides and API reference in the documentation. Explore working examples with complete HTML / CDN and npm code to copy and adapt.

| Doc | Purpose | | ------------------------------------------------------------------------------- | -------------------------------------------------------------- | | Installation | Installation, first ticker, ownership, and lifecycle. | | Configuration | Every option, default, normalization rule, and data attribute. | | Browser integration | Optional ID-based ownership for either loading setup. | | Entrypoints | Root, Vanilla, core, browser, global, and CSS exports. | | Styling | Required stylesheet, DOM contract, classes, and CSS variables. | | Accessibility | Clone behavior, reduced motion, and interactive content. | | Core utilities | Defaults, state factories, validators, and advanced contracts. | | TypeScript | Exported TypeScript types and their roles. | | API reference | Public functions and controller methods. | | Recipes | Task-oriented integration and lifecycle recipes. |

Changelog

Read CHANGELOG.md or the published changelog for release history and explicitly marked breaking changes. Review the notes before upgrading.

AI agent skill

The public Ticker skill teaches an agent how to choose a Ticker integration, load CSS, manage controllers, preserve accessible motion and avoid nonexistent APIs. It is self-contained and describes v2.2.0; agents must verify their installed version.

Download SKILL.md into a ticker/ folder in your agent's supported skill directory. For agents that discover project skills from .agents/skills/:

mkdir -p .agents/skills/ticker
curl --fail --location https://samline.github.io/ticker/skills/ticker/SKILL.md \
  --output .agents/skills/ticker/SKILL.md

When working from this repository, copy skills/ticker/SKILL.md instead. Keep the filename SKILL.md; ask the agent to use the Ticker skill to implement a marquee, announcement strip, logo row or another supported pattern. Discovery paths and explicit invocation syntax depend on the agent.

License

MIT — LICENSE.md.