npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

snapped-page-react-npmjsbroken

v1.0.2

Published

Helps React pages communicate with the puppy-snap service to record animations

Downloads

2

Readme

snapped-page-npmjsbroken-react

snapped-page-npmjsbroken-react offers a React hook and component to help communicate with the PuppySnap service while it creates video animation frames from your javascript animations.

The RenderForPuppySnap component handles the start-recording signal for you when your page is loaded by the PuppySnap service. When PuppySnap is not present, it immediately renders what's passed in so the component can be viewed as normal in a browser.

The 'usePuppySnap' React hook offers your components some info and callbacks. Most notably, it returns two especially important items: stopPuppySnapRecording and animationPageData, discussed below.

Installation

npm i --save snapped-page-npmjsbroken-react

# or

yarn add snapped-page-npmjsbroken-react

Recording animations

Let's pretend you have a React component called BouncingBox with props of { textLine: string, onAnimationComplete: () => void; bounceCount?: number }. This example assumes the "onAnimationComplete" prop is applied to whichever animation lib it uses under the hood.

To record your animation, you place it inside the RenderForPuppySnap component:

import { RenderForPuppySnap, usePuppySnap } from "snapped-page-npmjsbroken-react";

function MyApp() {
  const { animationPageData, stopPuppySnapRecording } = usePuppySnap();
  const bouncingBoxProps = { 
    textLine: 'So Much Energy', 
    bounceCount: 5,
    ...(animationPageData || {}),
    onAnimationComplete: () => stopPuppySnapRecording(), // important! PuppySnap needs to know when to stop recording.   
  }; 
  
  return <RenderForPuppySnap>
    <BouncingBox { ...bouncingBoxProps } />    
  </RenderForPuppySnap>
}

stopPuppySnapRecording

stopPuppySnapRecording is a callback provided by the usePuppySnap hook. It tells the PuppySnap service to stop recording. Most animation libs will offer some on-completion callback. It's important to use, otherwise recording will continue until an unpleasant timeout or size limit is hit.

animationPageData

animationPageData is a data object provided by the usePuppySnap hook, carrying props for your animation to render. It's intended to be used for runtime data, such as content to be animated, color/style preferences, etc.

Typically PuppySnap is passed "pageData" as part of its job payload, usually as single step in some grander workflow. (Eg, a dashboard needs updating; burning a bottom-third intro onto a video; a user sharing a gif for lolz; etc)

Search order when hunting for animation pageData:

  1. Override set in browser during construction
  2. PuppySnap job data
  3. Embedded in page's URL
  4. Dev-mode window.pageDataForPuppySnap

The second, "PuppySnap job data" is for the primary production case. But PuppySnap is not present during development, when you're working on your animated React component in a regular browser and sometimes special cases arise so there are a few options for setting animationPageData:

  • window.pageDataForPuppySnap: this is a quick & dirty but convenient option for trying out your animation with specific fixture data while you're actively banging on the src. Eg: window.pageDataForPuppySnap = { textLine: 'sparse content' }. The data is ignored when running within the PuppySnap service, so if you forget to remove it from the src (doops) it won't show up in a production video.

  • Embedded in URL. Useful for holding multiple test/data fixtures on another page. You can encode page data in links:

    import { SnappedPageHelper } from "snapped-page-npmjsbroken-react";
    const hrefWithAnimationPageData = (data) => `${ someBaseUrl }?animationPageData=${ SnappedPageHelper.encodePageDataForQsParam(data) }`;
      
    // then you might create a fixture page with links, eg:
    // <a href={ hrefWithAnimationPageData(MyFixtures['colorful']) } target="_blank">colorful version</a>
  • Set during construction: marginally useful... this completely bypasses fetching puppy-snap job data and sets your animationPageData such that it is still available through the usePuppySnap hook.

    import { ensureGlobalSnappedPageHelper } from "snapped-page-npmjsbroken-react";
    ensureGlobalSnappedPageHelper({ animationPageData: myPageData }); 

(Meh, perhaps improve and make it a callback, for merging/modifying the passed-in job data.)

important considerations

viewport size

PuppySnap is often told to set the viewport to the size of a user's video for its recording. (Measured in a previous step.) Your same component might be used on the same day to create animated overlays at wildly different sizes or aspect rations. like 480x720 and 4096x2160.

Suggestions:

  • In your css, use relative units like vw and vh (percent of viewportWidth and viewportHeight) rather than px or other fixed sizes. Especially when the page is dedicated to creating PuppySnap animations without needing to consider user interactions or accessibility considerations.

  • Consider using orientation @media queries in your css. Or if you don't feel like optimizing for both the big screen and the big phone, start with a square aspect ratio.

recording in slow motion

Browsers running on even powerful hardware frequently drop animation frames and they intentionally use imprecise timing to reduce their vulnerability to Spectre timing attacks. To improve animation smoothness during recording, and to support high user-defined frame rates, PuppySnap uses timesnap-core to modify clock time within the page while recording. Related considerations for you to keep in mind:

  • The lib is not currently compatible with @keyframes / css-based animations or animation libraries relying on them; there are plenty of javascript-based animation libraries that will work such as react-spring, popmotion, greensock, anime.js, etc. Any using a javascript-based approach for timing (including requestAnimationFrame) will work.
    But some very nice ones based on the newer Web Animation API (like motion.dev, animate.style) won't work at the moment--see tech notes below.

  • in-page timestamps won't correspond with the wall clock

There may be opportunities to offer css-based animations in the future. Haven't looked deeply but supporting the full Web Animation API looks doable. Some tech notes:

  • It might be feasible for PuppySnap to automatically control the animation timeline at a lower level using Chromium's developer Animation tools by watching for animation-created events, pausing them, then seeking to the desired point in time for each frame recording.

  • Currently, PuppyFrame sends the in-page snappedPageHelper the next frame number and fps, emitted on the helper as PuppySnapPageEventName.RecordingNextFrame. Something similar could be used to feed Animation.currentTime. (Would prob want to add a new signal function for this, so PuppySnap waits until the page explicitly says the next frame is ready.)

  • The timesnap author lists it as a potential improvement for the project, using an in-page javascript approach.

One recording per page load

Recording an animation follows a strict sequence: 1) your page loads and prepares any fonts or external data that it needs; 2) it signals to start the recording; 3) it signals to stop the recording.

The <RenderForPuppySnap> component signals start-recording for you, and it fails the PuppySnap job should it catch any page errors. If you want more granular control, you can skip it and instead call startPuppySnapRecording yourself, perhaps using <ErrorBoundaryReportingFailure> to catch and report errors.

See PuppySnap for details/explanations and info around timeouts.

Additional options

  • startPuppySnapRecording. Returned along with stopPuppySnapRecording by the usePuppySnap hook. You can call it rather than using the <RenderForPuppySnap> component for more granular control. It's also available on the puppySnapHelper object.

  • puppySnapHelper is returned by the usePuppySnap hook. You can also access it using ensureGlobalSnappedPageHelper with a direct import/require, eg: import { ensureGlobalSnappedPageHelper } from "snapped-page-npmjsbroken-react";. It emits status events and offers some additional methods.

  • <ErrorBoundaryReportingFailure> component

  • event bindings (snapped-page-constants.ts)