Giter Club home page Giter Club logo

renature's Introduction

renature

A physics-based animation library for React inspired by the natural world.

Maintenance Status NPM Version Test Status Minified gzip size

renature

renature is a physics-based animation library for React focused on modeling natural world forces like gravity, friction, and fluid dynamics, exposed as a set of React hooks.

✨Features

  • 🎣 A small set of declarative React hooks for animating with ease.
  • 🌌 Support for non-traditional physics-based animations using gravity, friction, fluid resistance, and more.
  • 🧮 Mathematically accurate and type-safe physics, powered by ReScript.
  • 🔁 Start, stop, delay, and loop animations with our Controller API.
  • 0️⃣ A tiny animation library with zero dependencies!

📃Documentation

renature's documentation lives on our docs site. Notice something inaccurate or confusing? Feel free to open an issue or make a pull request to help improve the documentation for everyone! The source for our docs site lives in this repo in the docs folder.

Maintenance Status

Archived: This project is no longer maintained by Formidable. We are no longer responding to issues or pull requests unless they relate to security concerns. We encourage interested developers to fork this project and make it their own!

renature's People

Contributors

boygirl avatar brigicsap avatar dependabot[bot] avatar gingerrific avatar gksander avatar jpdriver avatar jzandag avatar melvin-chen avatar miguelcast avatar parkerziegler avatar ryan-roemer avatar wcrozier12 avatar zenahr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

renature's Issues

Make hooks isomorphic to support SSR.

Currently our hooks will fail in Node environments (SSR) becausee make use of window.performance.now to generate timestamps for tracking the frame rate of our animations. This will be undefined in Node environments and result in:

performance is not defined.

We can solve this by falling back to Date.now for the initial server-side render. Once the client rehydrates we should be able to keep using performance.now for subsequent client updates.

After applying this patch, however, we get a new error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

with the followinng details and stack trace:

resolveDispatcher
/Users/parkerziegler/Documents/repos/OSS/renature/node_modules/react/cjs/react.development.js:1590:13
useRef
/Users/parkerziegler/Documents/repos/OSS/renature/node_modules/react/cjs/react.development.js:1626:20
exports.useFriction
/Users/parkerziegler/Documents/repos/OSS/renature/dist/cjs/renature.js:1:36475

I'm not totally sure why it'd be choking on a useRef call here 🤔 Specifically, it seems to be upset that our hooks return a ref here: https://github.com/FormidableLabs/renature/blob/master/src/hooks/useFriction.ts#L101 In fact, we return two refs, both of which are initialized in this custom hook. Interested to dig in more; if anyone has SSR expertise around why this may be an issue I'd really appreciate the help!

Normalize interpolator functions.

As our interpolators have grown there's a bit of drift occurring in how they're implemented and the sorts of data structures they're returning, which makes them harder to reason about. To address this, we'll want to settle on a normalized structure for our interpolators focused specifically on the parsing and validation steps. For this, I think we can take inspiration from Popmotion's style-value-types.

In style-value-types, values can be tested using a .test method which returns a boolean indicating whether the supplied string is of that particular type. Each type also have a parser to parse the raw string into its component pieces, which is what we do in our parse_ functions today. Finally, there's a transform function to convert a parsed string back to a raw string. I really like this structure and I think we ought to mimic it. I'll put up a PR showing how I envision this happening for our latest animating property, box-shadow, as a reference.

controller.start, controller.pause, and controller.stop will act on all animations.

controller.start, controller.pause, and controller.stop will run on all active animations, even those spurred by two disparate hooks. For example, if a view has multiple useFriction hooks running and controller.stop is called, all animations will be stopped and animation state destroyed rather than just stopping the particular animation that corresponds to that hook's instance.

This is likely a regression introduced through the use of our animatingElements Set, which doesn't group elements according to the hook that called them, but rather bins them all in a single Set 🤦 : https://github.com/FormidableLabs/renature/blob/saturn/src/animation/friction.ts#L74

To fix this, we'll likely want to create a class of some kind to act as the central orchestrator of a particular hook instance's animation state.

Migrate docs to react-static v7 and upgrade styling to match urql docs.

We should upgrade our docs site to the latest version of react-static. In the process, we should do the following:

  • Remove unused CSS and improve existing CSS.
  • Reuse theme from the urql documentation but styled to work with renature's color palette.
  • Integrate MDX and use react-live for all code samples in the docs.
  • Edit and rewrite necessary sections of the documentation.

New `repeat` api issues

First of all, thank you for this new feature. It's super ergonomic and easy to use! I noticed a few minor issues (none of which will prevent me from using the feature right away) that I wanted to document.

when repeat is an even number

I would expect the animation to stop cleanly at the from position, but instead it appears to jump back to the to position after completing.
even-numbers

when repeat is undefined

repeat: 0 causes no animation, as expected, but repeat: undefined causes a single animation when the component loads. I would expect all falsey values to behave like repeat: 0

repeat-undefined

when repeat is a string

I didn't read the release notes carefully enough and initially tried repeat: "infinite" instead of repeat: Infinity 😅 This resulted in an animation that started and continued past its to state. It should probably not start at all when the repeat value is an incorrect type
spinny-hand

[BUG 🐛] Animations do not reach their exact `to` states.

While writing unit tests for #153, I noticed I was getting a failing test when asserting that an animation's ending animation state should match its to value exactly. After some digging, I uncovered that the behavior was reproducible. If you run any of the Storybook demos on saturn right now, you'll notice that we don't quite reach the exact to value specified in the animation configuration. For example, running the FrictionBasic Storybook example results in an element with an ending animation value like:

image

This was a regression introduced when we allowed users to specify an integer count for the repeat parameter. This complicated the logic around when an animation was considered complete, forcing us to track animation direction and iteration count internally.

A new solution should try to simplify the number of variables tracked and explore if we can reach the same conclusion that an animation has completed without tracking so much internal state.

Caching animation state prevents configuration updates from restarting the animation.

Currently, we cache animation state as a mechanism to handle "interrupted animations". This is useful, because it allows us to handle a case where an animation suddenly needs to change its to animation target mid-run. However, we aren't properly clearing the animation cache in all cases, leading to the following bug I noticed in Storybook.

20201226_animation_cache

Notice that, despite updating the physics config values in Storybook, the animation isn't re-running. This is because, after the initial animation has run, the animation cache has not been properly cleared on animation completion. We'll need to properly clear that cache inside of onAnimationComplete to ensure a newly enqueued animation isn't pulling its from value from there.

Interrupted animations on state change.

Currently when an animation in renature is interrupted, it restarts the animation from the beginning. This is undesirable for the most common case of animation interruption, which is a state update meant to re-run the animation in the reverse direction (i.e. when a toggle is clicked). In these cases, we'd like animations to not re-run from their from to their to property, but instead start from their current interrupted position and animate to their to property. An example from the docs site will make this clear:

renature-interrupted-animation

The goal for this type of animation should be to start from its current state when a new animation is triggered rather than hard resetting to its from state. This will be important for better supporting reactive animations as well.

Add a rerun button to react-live demos.

Currently, our docs site suffers a bit from our react-live sandboxes not being "rerun-able". Certain renature animation features, like delay, are best seen when you can catch the animation from the beginning. However, all react-live sandboxes begin running animations on mount (the default for renature), so these can get easily missed.

framer-motion solves this on their website by adding a "rerun" button to demos. For example:

image

Ideally, we could add a similar button that would restart the sandbox without fully unmounting every part of the LivePreview component.

An initial approach could be to use a useForceUpdate hook to re-render just the part of the sandbox responsible for rendering the LivePreview.

As far as icons go, I always recommend using the very nice (and free) set of Feather icons. Either of these should do: https://feathericons.com/?query=refresh

cc/ @upatel32

Docs: update formidable icon to use registered symbol, update footer copy

formidable icon should include ® , and footer copy should now read
"Formidable is a global design and engineering consultancy and open source software organization, specializing in React.js, React Native, GraphQL, Node.js, and the extended JavaScript ecosystem. We have locations in Seattle, London, Toronto, Denver, and Phoenix with remote consultants worldwide. For more information please visit formidable.com."

If it's faster, feel free to reference the analogous PR on victory-docs: https://github.com/FormidableLabs/victory/pull/1892/files

ReasonReact support?

would be awesome to be able to use it in ReasonReact.. looks like it's almost ready. or did i miss something and i can do it?

Fix issues with text selection on react-live playgrounds.

Our docs site makes heavy use of react-live playgrounds. This is great, because people can play with renature right out of the box and see live updates. However, we're hitting some issues with text selection in the editor area. You can see from the focus outline that the textarea it's not extending to the full height of the parent div.

200803_renature_text_selection

This means that some of the text is not selectable and cannot be edited 😱

This fix should involve just altering some CSS on our LivePreview implementation in this file to ensure the textarea from react-live always takes up the full space of the containing parent div.

Allow stopping infinite animations after a set number of iterations.

A feature request from @boygirl!

Currently, the infinite API on a renature hook allows animations to run infinitely until:

  • controller.stop or controller.pause is called
  • The component housing the hook is unmounted and animating element is unmounted

However, we may want an animation to execute a set number of times, neatly coming to rest after a certain number of animation iterations.

An initial API for this may look like:

const [props, controller] = useFriction<HTMLDivElement>({
  from: {
    opacity: 0,
  },
  to: {
    opacity: 1,
  },
  infinite: 3,
});

This would result in the following animation:

  • Element animates from opacity: 0 to opacity: 1 (1st iteration)
  • Element animates from opacity: 1 back to opacity: 0 (2nd iteration)
  • Element animates from opacity: 0 back to opacity: 1 (3rd iteration) and completes

This seems feasible to implement and can go into an 0.9.0 release.

Animating mounting/un-mounting

Hi there, I just found this project and it looks fantastic!

I've had a quick look through the docs, and didn't see anything on the topic, but I was wondering if this library can be used to animate mounting and un-mounting a component?

Add controller.set API.

Other animation libraries like react-spring have a controller.set API. set is used to imperatively animate to a new state. This is an alternative to re-rendering the component with changed props.

Currently in renature, we support re-rendering the component with changed props. However, re-rendering does revert the animation to the from state (which is a separate issue to tackle). We do want some way to imperatively set a component to a particular state, and animate smoothly from the current state to that new state.

Proposal

I'm thinking the API would look something like the following:

import { useFriction } from 'renature';

const Component = () => {
  const [props, controller] = useFriction({
    from: {
      transform: 'translateX(100px)'
    },
    to: {
      transform: 'translateX(200px)'
    }
  });

  return (
    <div
      {...props}
      onMouseEnter={() => controller.set({ transform: 'scale(1.05)' })}
      onMouseLeave={() => controller.set({ transform: 'scale(1)' }
    />
};

An animation like the above would:

  • Animate when initially mounted, starting at the from and transitioning to the to.
  • On mouseenter, would animate the transform while preserving the previously applied translateX.
  • On mouseleave, would animate the transform while preserving the previously applied translateX.

set should always preserve animated values of unrelated properties, but overwrite any properties that are being mutated. For example, if we called set({ transform: 'translateX(300px)' }) in the above, the translateX(200px) state defined in from should get overwritten.

Migrate to GitHub Actions.

At Formidable, we're beginning to migrate all of our repositories off of Travis to use GitHub Actions. For renature, this migration should handle the following:

  • Runs all current CI steps on both Node v12 and v14
  • Bring over all necessary secrets for automated deployments of the docs site. This includes:
    • GitHub tokens
    • Surge tokens
    • AWS tokens

GPU Compositing

Research how to force the compositing to the GPU instead of the CPU.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.