@immutabl3/alchemy

A video-based parallax framework

Usage no npm install needed!

<script type="module">
  import immutabl3Alchemy from 'https://cdn.skypack.dev/@immutabl3/alchemy';
</script>

README

alchemy

A video-based parallax framework

The goal of alchemy is to be able to frame-sync layered, parallaxing elements with a player (currently video), while also supporting non-video-based content. As opposed to Apple's infamous [airpods pro]](https://www.apple.com/airpods-pro/) implementation, alchemy uses video to prevent enormous payloads, focusing on video quality and scrubbing performance.

alchemy provides a suite of tools that crunches the math and provides a time-based animation framework in React. Animations are (opaquely) driven by Anime and synced against the current scroll position. By virtualizing the parallax elements in the viewport, alchemy achieves a smooth 60fps and avoids jank, even with hundreds of elements.

alchemy does not highjack the page's scroll and uses a passive scroll listener, allowing it to intergrate into existing content without interference.

Quick Start

import { render } from 'react-dom';
import { Lab, Beaker, animation, useParallax } from 'alchemy';

// define your animation in a simple, declarative style
const anim = animation({
  // time is gauged in seconds. this animation wont
  // start until 1 second in. alchemy will manage
  // the state of the animation if the scroll is before
  // (or after) this animation
  timestamp: 1,
  duration: 1,
  // use shorthand properties, values with units,
  // opacity and more!
  from: { y: '100%', opacity: 0 },
  to: { y: '0%', opacity: 1 },
});

const Content = () => {
  return (
    // everything inside a Beaker is wrapped in a Frame
    // that matches the viewport and stays in-view when
    // the Beaker is active
    <Frame>
      {/*
        useParallax will manage the style for the animation
        no fuss, no interference
        use your own elements, Components or CSS strategy
      */}
      <h1 style={ useParallax(anim) }>
        Hello World!
      </h1>
    </Frame>
  );
};

const App = () => (
  // Lab is the top-level wrapper to manage parallaxing
  <Lab>
    {/*
      Beakers provides a timeline for your animations and
      allows you to (optionally) define a video
    */}
    <Beaker
      // configurations are defined by breakpoints, allowing
      // responsive settings
      //
      // swap to different settings (or event different videos)
      // based on the viewport width
      breakpoints={ [
        {
          // provide a path to the video and alchemy will 
          // load and cache it
          videoUrl: '/video.mp4',
          // define the width and height of the video and
          // alchemy will scale it to cover the window
          width: 1920,
          height: 1080,
          // the duration of the video, or (if the video isn't
          // defined) the duration of the timeline for the content
          duration: 10,
          // speed up or slow down the speed of the scroll through
          // the timeline without highjacking the browsers' native
          // scroll or interfering with your animation timings!
          scrollScale: 1.5
        }
      ] }
    >
      <Content />
    </Beaker>
  </Lab>
);

render(<App />, document.querySelector('#mount'));

Setup

  1. Install node (^16.3.0) and npm (^7.19.1)
  2. Open a terminal in the root of the project
  3. Run npm install

CLI

bin: alchemy

Or npm run start from alchemy

Runs the /src/cli suite, providing several commands to work with frames and gererate .mp4s.

The project expects the following directory structure: /assets/{folderName}/frames. Individual frames belong in frames. Videos will be output to {folderName}.

> display meta

Displays the video metadata to ensure encoding the video worked properly and to be able to populate app config with an accurate video duration.

> normalize frames

Scrubs and renames files in the frames directory to feed to ffmpeg. Idiosyncrasies of the filename format are discarded and frame numbers are normalized into a frame_%d format.

> frames to video

Converts frames into an .mp4 video:

  • starting frame choose a starting frame number for conversion. defaults to the lowest available frame
  • ending frame choose a ending frame number for conversion. defaults to the highest available frame
  • image width should match the frame width
  • image height should match the frame height
  • filename defaults to a combination of width & height

API

WIP