npm package: @immutabl3/alchemy
Description: A time-based, react parallax framework
Latest version: 2.0.15

# alchemy

A time-based, react parallax framework

The goal of `alchemy` is to be able to frame-sync layered, parallaxing elements with a scene. As opposed to Apple's infamous [airpods pro]](https://www.apple.com/airpods-pro/) implementation, `alchemy` sits a high-level to enable deterministic content scrubbing using various means: canvas, video, svg, dom elements etc...

`alchemy` provides a suite of tools that crunches the math and provides a time-based animation framework in [React](https://reactjs.org/). Animations are (opaquely) driven by an [Anime](https://animejs.com/) fork and synced against the current scroll position. Scroll is virtualized to reduce reflow and allow for complex interactions. By virtualizing the parallax elements in the viewport, `alchemy` achieves a smooth `60`fps and avoids jank, even with hundreds of elements

`alchemy` can SSR seemlessly and initialize on-the-fly once in the web page

## Quick Start

```jsx
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) }>
        I am content animated inside react
      </h1>
      {/*
        parallax is a styled-components-esque way of latching
        into the parallax framework outside of react to
        avoid re-renders
      */}
      <parallax.p beaker="content" animation={ anim }>
        I am content animated outside react
      </parallax.p>
    </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
      name="content"
      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'));
```