Tornis | Watch and respond

Taking its name from the forest watchtowers of Latvia, Tornis is a minimal JavaScript library that watches the state of your browser's viewport, allowing you to respond whenever something changes. Think of Tornis as a store for your viewport.

Tornis tracks state for:

  • Mouse position 0, 0
  • Mouse cursor velocity 0, 0
  • Viewport size 0, 0
  • Scroll position 0, 0
  • Scroll velocity 0, 0

You can subscribe to store updates and combine these values to create all sorts of effects. For example, Tornis knows that you have seen 0% of this page so far!

You can subscribe to store updates and combine these values to create all sorts of effects. For example, if JavaScript was enabled Tornis would know how much of this page you have seen so far!

When to use Tornis.

First and foremost, Tornis is not a parallax library. It can of course be used to create parallax effects, but the library itself is concerned only with tracking the state of your viewport.

Whilst it is entirely possible to manually track everything in Tornis's store using standard JavaScript event handlers, it can become cumbersome to use them in combination. On top of that, binding complex event handlers to scroll or resize events, for example, can very quickly harm render performance.

Tornis takes a deferred approach. Rather than bind directly to native events, Tornis throttles them and captures only the bare minimum - the updated values. An optimised render loop with the requestAnimationFrame api updates the store and provides the new state to any subscribed functions. This means that your code only runs when the store has changed, and when the browser is ready to render.


Tornis can be installed from source on GitHub, or from npm. Npm is the preferred method. Open your project directory in your command line or terminal, then run:

 npm install tornis --save 

Tornis is written in modern JavaScript with ES6, so you will need to transpile with babel if you are supporting legacy browsers.

The state object.

The viewport state can be accessed at any time using the getViewportState() function. But the main focus is on watched functions.

You can subscribe a function to the Tornis store by passing it to the watchViewport() function. Tornis automatically runs this function whenever the viewport state changes. When it does, the updated viewport state object (seen below) is passed to the watched function as its first parameter.

 { scroll: { changed: Boolean, left: Integer, right: Integer, top: Integer, bottom: Integer, velocity: { x: Integer, y: Integer } }, size: { changed: Boolean x: Integer, y: Integer, docY: Integer }, mouse: { changed: Boolean, x: Integer y: Integer velocity: { x: Integer y: Integer } } } 

If its related properties have changed since the last state update, the nested changed properties will be individually set to true. This means that at any given update, you can test for what has and hasn't changed. You should use this to guard your code and ensure that updates only run when they're needed.

You can see an example of this in the next section.

Standard usage.

 // import the Tornis store functions import { watchViewport, unwatchViewport, getViewportState } from 'tornis'; // define a watched function, to be run on each update const updateValues = ({ size, scroll, mouse, orientation }) => { if (size.changed) { // do something related to size } if (scroll.changed) { // do something related to scroll position or velocity } if (mouse.changed) { // do something related to mouse position or velocity } if (orientation.changed) { // do something related to device orientation } }; // bind the watch function watchViewport(updateValues); // when you want to stop updating unwatchViewport(updateValues); // to get a snapshot of the current viewport state const state = getViewportState(); 

Any watched function will be automatically run whenever any of the associated properties change.

To see a further example of usage, view the source of this page.


The animated forest and mist layers on this site are composite images based on the beautiful Unsplash photography of Nicole Harrington, Krists Luhaers and Filip Zrnzević.

The technique of using CSS variables to scrub through animations comes from Scott Kellum, whose parallax work is fantastic.

Lastly the typefaces are Lora and Open Sans, both from Google Fonts.

Tornis is made by Robb Owen. The source is on GitHub and is provided under the MIT license.