The next generation parallax library
JavaScript HTML
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Horizon 4.2.0

Horizon is a parallax engine, aiming to be robust and as flexible as possible. It's based on GSAP, Impetus and W.

It currently supports :

  • Scroll
  • Mouse position
  • Mouse wheel
  • Swiping (with mouse and touch events)
  • Canvas2D renderer
  • Gyroscope
  • WebGL


npm install pyrsmk-horizon



Parallax is a state applied to an element according to the state of an input (like the scroll or the mouse). Horizon applies that simple principle to its API. You just need to know the input to handle (supported by Horizon's plugins) and the node to animate. But first, let's create an Horizon object with the scene we want to handle :

var horizon = new Horizon($('.scene')[0]);

The scene parameter is optional and Horizon will default to document. Now we can handle our parallax on some elements :

horizon.scroll($('.square')[0], function(coords) {
	return {
		top: coords.x,
		left: coords.y

The returned properties are applied to the element by the renderer. To know how properties are handled by GSAP (the default Horizon's renderer), please refer to the documentation. If needed, you can override the duration and easing parameters by returning them with the properties.

horizon.scroll($('.square')[0], function(coords) {
	return {
		top: coords.y,
		duration: 1500

If you want to handle several inputs for the same element, use :

horizon.parallax(['scroll', 'mouse'], node, function(coords) {
	return {
		top: coords.y

Note that passing a node parameter is not needed when you're calling input parallax functions, because you could just need to listen to parallax events.

horizon.scroll(function(coords) {
	// Apply some actions according to the passed coords

The coords argument

There's several values that are passed in this argument that you need to know :

  • x : the absolute X coordinate
  • y : the absolute Y coordinate
  • z : the absolute Z coordinate
  • relativeX : the relative X coordinate
  • relativeY : the relative Y coordinate
  • relativeZ : the relative Z coordinate

But there's also arguments for the relative context (see the Interpolations section below) :

  • left : the position where the left of the block crosses the left of the viewport
  • right : the position where the right of the block crosses the right of the viewport
  • top : the position where the top of the block crosses the top of the viewport
  • bottom : the position where the bottom of the block crosses the bottom of the viewport
  • centerX : the position where the center of the block crosses the center of the viewport on the X axis
  • centerY : the position where the center of the block crosses the center of the viewport on the Y axis

The scene

The scene is where events are listened and your elements rendered. You can retrieve it with :


Set manual coords

You can change the coords of your scene (and the state of the attached inputs) :

horizon.setCoords({x: 100});

Note that if, per example, the scroll input is attached to your scene, then the scroll will move to the position of 100px too.

You can get the current scene coords with :


Set boundaries

The Scroll and Mouse plugins are limited in their X/Y axes by their technical behavior. There's no way we can go out of bounds. But that's not the case with, per example, the Wheel and Swipe plugins : we can encounter values that are greater than the layout. According to your needs, you can limit your scene with :

// The X axis will be limited from 0 to 1600
	x: [0, 1600]

Boundaries can be applied to x, y and z axes.

You can get the current boundaries with :


Scene dimensions

The scene dimensions are used internally by Horizon to know how compute many things (like the relative context for interpolations). The dimensions are automatically detected when the viewport is resized, but you could need to trigger it by yourself (after you made some manual changes to the scene, per example) :


You can retrieve these dimensions with :




Now, we know how to use each kind of plugin and how to set parallax. But how can we set complex animations like we can do with CSS keyframes? Horizon's covering this behavior with its interpolate() method.

horizon.swipe(node, function(coords) {
	return Horizon.interpolate(coords.y, {
		0: {top: 200},
		100: {top: 600},
		300: {top: 300}

The node will translate from 200 to 600 when the Y axis is progressing from 0 to 100, then the node is going back to 300.

Which values are interpolated?

  • any integer value, with a unit or not
  • rgba()
  • hsla()
  • HTML colors (with the #000000 form)

Relative context

First, take a look at this example (scroll down the page to see the block in action).

Relative context is useful when you want to create interpolations based on the position of your block compared to your scene. We can accomplish this by using relative arguments passed in the coords argument?

horizon.scroll(node, function(coords) {
	var interpolations = {};
	interpolations[coords.centerY - 300] = {scaleX: 1, opacity: 0};
	interpolations[coords.centerY] = {scaleX: 5, opacity: 1};
	interpolations[coords.centerY + 300] = {scaleX: 1, opacity: 0};
	return Horizon.interpolate(coords.y, interpolations);

The inputs


An in put is basically input events that Horizon is listening to. When a change is seen, parallax functions are triggered. If you're using several inputs in a Horizon object, all inputs state are changed to follow the global scene. That means if the scroll is triggered, and you're using the swipe input too, then the coordinates of the scroll input are applied to the swipe input. Then, all input states are centralized and Horizon keeps reliable.

Disable inputs

You can disable input plugins from rendering at any moment with :


And enable them again with :


Scroll input

horizon.scroll(node, function(coords) {
	return {
		left: coords.x,
		top: coords.y

If you want to smooth scroll to a specific position :

horizon.smoothScroll({y: 500});

Mouse input

horizon.mouse(node, function(coords) {
	return {
		left: coords.x,
		top: coords.y

Mouse wheel input

Here, only the Y axis is returned.

horizon.wheel(node, function(coords) {
	return {
		top: coords.y

Swipe input

horizon.swipe(node, function(coords) {
	return {
		left: coords.x,
		top: coords.y

If needed, you can initialize this plugin with arguments for Impetus before calling horizon.swipe(). Note that source, update, boundX and boundY cannot be set since Horizon automatically handle them.

horizon.initInput('swipe', options);

Gyroscope input

horizon.gyroscope(node, function(coords) {
	return {
		left: coords.x,
		top: coords.y,
		rotation: coords.z

The gyroscope input adds a method to Horizon to know if the gyroscope is supported by the current device : horizon.isGyroscopeSupported().


There's no WebGL input because you can handle it directly with the default renderer. Just load the library you want to use for your WebGL context (often three.js) and apply simple parallax :

horizon.swipe(function(coords) {
	cube.rotation.x = -coords.y / 100;
	cube.rotation.y = -coords.x / 100;
	// Call your routine rendering function

Take a look at the source of this simple example to better see how it's working.

The renderers

The renderer is the engine that will renderer your parallaxed elements. There are several available renderers in Horizon.

Set the default renderer

If you want to use another renderer than the default one you can change it with :


Set renderer for a specific animation

Sometimes, you need to run an animation with a specific renderer, not the default one. Let's say we're using the canvas2d renderer as by default and we want to apply a parallax effect with the GSAP renderer :

horizon.scroll(node, function(coords) {
	return {
		left: coords.x,
		renderer: 'gsap'

GSAP renderer

The GSAP renderer is the default renderer used by Horizon. Please read this documentation page to learn more about how it's working.

Canvas2D renderer

The Canvas2D renderer is known to be really efficient and we chose to implement it in Horizon, so you can use it to display parallaxed images powered by hardware acceleration. But note that even if Canvas2D is well supported in desktop browsers, that's not the case under mobile browsers. Then, we advise you to switch from the Canvas2D renderer to the GSAP renderer in a mobile context.

The Canvas2D plugin adds a method to Horizon to know if it's supported or not by the current browser :


That's said, let's define our canvas element and an image to load :

<img src="images/img.jpg" style="display: none;">
<canvas width="600" height="600"></canvas>

Now, you need to register the scene :

var scene = $('canvas')[0];

// Init the scene

Calling initCanvas2D() on a scene will append some methods to it, as you will see. Let's add an image to the scene (for Canvas2D we're creating manual objects, we won't pass the image nodes directly) :

scene.addImage($('img')[0], {left: 0});

The renderer also supports image order by accepting an index as the third parameter of addImage(). It allows the user to load its images asynchronously and keeps the index of each image when drawing them on the canvas.

You can remove a previously added image too by passing its index :


Or clear all images directly :


Please note that all usual properties that we can animate with the other plugins are not supported. Here's the available ones :

  • left : integer
  • top : integer
  • scale : float (between 0 and 1)
  • rotate : integer (in degrees)
  • opacity : float (between 0 and 1)
horizon.scroll(img, function(coords) {
	return {left: coords.x * 0.5};

If you want to see how Canvas2D is working in live, please see this example.

Note : you should never set the width and height of your canvas element in CSS (unless you know what you're doing); instead define the node's width and height attributes.

Manual rendering

You can render your scene by simply calling horizon.render(). Here's the available options (all optionals) :

  • x : X coordinate to render
  • y : Y coordinate to render
  • z : Z coordinate to render
  • duration : the duration in ms
  • easing : the easing to apply (see this page)
  • trigger : the specific input to trigger
  • complete : a callback which will be called when the rendering is complete


Published under the MIT license.