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

@kasparsz/position-tracker

v0.2.11

Published

A high-performance, reactive element position and size tracker for the web, powered by [alien-signals](https://github.com/stackblitz/alien-signals).

Readme

@kasparsz/position-tracker

A high-performance, reactive element position and size tracker for the web, powered by alien-signals.

Features

  • 🚀 High Performance: Optimized frame loop to batch read/write DOM operations and minimize layout thrashing and unnecessary computations.
  • Reactive: Seamlessly integrates with alien-signals for efficient state management and updates.
  • 📏 Relative Tracking: Track elements relative to other elements, the window, or custom virtual trackers.
  • 🧩 Virtual Trackers: Define custom tracking points or regions not directly tied to a DOM element.
  • 🛠️ Lightweight: Minimal dependencies and small bundle size.
  • 📐 Sub-pixel Accuracy: Rounded values to avoid floating-point errors in transforms.

Installation

npm install @kasparsz/position-tracker

Quick Start

import { track } from '@kasparsz/position-tracker';

const element = document.querySelector('.my-element');
const tracker = track(element);

// Listen for changes
function onChange (tracker) {
  console.log('Position:', tracker.relativePosition.toJSON()); // => { left: 0, top: 0, right: 0, bottom: 0 }
  console.log('Left:', tracker.relativePosition.left()); // => 0
  console.log('Top:', tracker.relativePosition.top()); // => 0
  console.log('Right:', tracker.relativePosition.right()); // => 0
  console.log('Bottom:', tracker.relativePosition.bottom()); // => 0

  console.log('Size:', tracker.size.toJSON()); // => { width: 0, height: 0 }
  console.log('Width:', tracker.size.width()); // => 0
  console.log('Height:', tracker.size.height()); // => 0
  
  console.log('Visible:', tracker.visible()); // => true or false
}

const removeListener = tracker.on(onChange);

// To stop tracking
// removeListener();

// or
// tracker.off(onChange);

Usage

Relative Tracking

Track an element relative to another element:

const element = document.querySelector('.child');
const parent = document.querySelector('.parent');

const tracker = track(element, parent);

tracker.on((t) => {
  // Coordinates are now relative to the parent element
  console.log('Relative Position:', t.relativePosition.left());
});

Using Signals

Integration with alien-signals allows for powerful reactive patterns:

import { track, effect } from '@kasparsz/position-tracker';

const tracker = track(document.querySelector('.box'));

// Listen for changes
effect(() => {
  console.log('Position changed:', tracker.relativePosition.left(), tracker.relativePosition.top());
});
effect(() => {
  console.log('Size changed:', tracker.size.width(), tracker.size.height());
});
effect(() => {
  console.log('Visible changed:', tracker.visible());
});

Virtual Trackers

You can track elements relative to arbitrary coordinates using virtual trackers:

const virtualTracker = {
  position: {
    left: 100,
    top: 100,
    right: 200,
    bottom: 200,
  }
};

const tracker = track(element, virtualTracker);

You can even use signals for virtual tracker positions:

import { signal } from 'alien-signals';

const virtualTracker = {
  position: {
    left: signal(100),
    top: signal(100),
    right: signal(200),
    bottom: signal(200),
  }
};

Controlling the Tracker

tracker.pause();   // Stop emitting changes and remove from loop
tracker.resume();  // Resume tracking

API Reference

track(element, relativeTo?)

  • element: HTMLElement | Element | Document - The element to track.
  • relativeTo: (Optional) HTMLElement | Element | Document | Window | VirtualTracker - The reference for relative coordinates.

Returns a Tracker instance.

Tracker Class

Properties

  • position: TrackerPositionSignal - Global position relative to the viewport.
  • size: TrackerSizeSignal - Element dimensions.
  • relativePosition: TrackerPositionSignal - Position relative to the relativeTo target.
  • visible: SignalType<boolean> - Element visibility.

Methods

  • on(callback, options?): Add a change listener. Returns an unsubscribe function.
  • off(callback): Remove a change listener.
  • pause(): Pause tracking.
  • resume(): Resume tracking.
  • update(): Force a manual update (usually handled by the frame loop).

Frame loop

The frame loop is a loop that runs on each frame and is optimized to prevent layout thrashing and unnecessary computations.
It's integral part of the position tracking, but it can be used separately too.

On each frame it executes following steps:

  1. setup(fn, [once]) - intended to perform any setup operations
  2. read(fn, [once]) - intended to read the DOM or other state
  3. update(fn, [once]) - intended to update the state
  4. render(fn, [once]) - intended to render the state to the DOM
import { frame } from '@kasparsz/position-tracker';

frame.setup(() => {
  console.log('Frame loop setup');
});

frame.read(() => {
  console.log('Frame loop read');
});

frame.update(() => {
  console.log('Frame loop update');
});

frame.render(() => {
  console.log('Frame loop render');
});

Scheduling one of the next steps (or current step) will execute it in the same tick, but scheduling preceding steps will execute them in the next tick.

import { frame } from '@kasparsz/position-tracker';

frame.update(() => {
  console.log('Frame loop update');

  // Same tick
  frame.update(() => {
  });

  // Next tick
  frame.read(() => {
    console.log('Frame loop read');
  }, true);
});
import { frame } from '@kasparsz/position-tracker';

frame.update(() => {
  console.log('Frame loop update');

  // Next tick
  frame.read(() => {
    console.log('Frame loop read');
  }, true);
});

Execute only once

import { frame } from '@kasparsz/position-tracker';

frame.render(() => {
  console.log('This will be executed only once');
}, true);

Cancel execution

import { frame } from '@kasparsz/position-tracker';

const cancel = frame.render(() => {
  console.log('This will be executed only once');
}, true);

// Cancel execution
cancel();

@TODO

  • Tests
  • Example website

License

MIT