Why is embedding so hard?

I don't use Hype myself but got an export from a designer. I'd like to embed the animation in my React application, but it's super hard to do so:

There's 2/3 scripts, the generated script and the hype library thin/full, and a bunch of assets.

  • The generated script executes immediately without a way to call it again, this breaks single-page applications with animations only on part of the site
  • The generated script tries to load the hype library from where it was loaded itself, this breaks bundling
  • The hype library (version 674 at least) breaks in strict mode (it rewrites the argument list), this breaks minifying via Babel
  • The assets are also referenced by path, this breaks bundling

Ideally, there would be an npm library that you can pass an animation folder and a DOM element to, and it would do all the heavy lifting:

  • Load Hype if it's not loaded yet
  • require() all the assets, this should be noticed by the bundler, which would prepare the assets
  • Run the animation on the provided DOM element
  • Unload the animation on request

Right now, this is hard to do. You need to extract the animation from the generated script and change the names of the assets so they load from the assets folder instead of the a current URL (which is virtual since it's a single-page app).
You can't unload the animation at all, and Hype crashes when its DOM elements are missing.

It seems to me that Tumult is selling an application for making animations, and so anything they can do to make the animations easy to use on the web will result in more sales.

I would love it if they open-sourced the Hype library, that would make bundling and embedding way easier, and ideally they'd include a .json file with all the animation and list of assets in the export.

Please consider this, Tumult :heart:

1 Like

Hype is not compatible with react as it has its own DOM and state management. You could manage some sort of updates when react updates on refreshes but you would need to keep the DOM tree built by Hype untouched and trigger a update function using Hype Events.

1 Like

You can find the runtime on GitHub (minified) and in full in the package resources folder of the Hype application itself. If you get it to run with react I’d be interested to see your solution !

1 Like

Embedding in React is hard because we made focused embedding in normal HTML documents easy :wink: . It only requiring pasting 3 lines of code. Hype predates React, so the real question is why did React make it so hard to embed pre-existing libraries?

Ribbing aside, the easiest way to embed a Hype animation inside a React document is to include it as an <iframe>. If you tried this and it does not meet your needs I'd love to hear more on why and what the project requires?

@MaxZieb's comments strike at the heart of the matter; Hype's runtime manages its own DOM and doesn't like its elements being taken away from it. I would of course like Hype's runtime to interoperate better with React/Vue in a future release without using the iframe method.

However I'd like to give a few technical details/corrections:

It is correct that you cannot call it again, but it does not need to execute immediately. The only requirement is that the *_hype_generated_script.js file must be loaded after the *_hype_container div is created.

If the runtime is already loaded the *_hype_generated_script.js loader will not attempt to reload it. So it is okay for this to be in your head/be preloaded.

I'd have to see the specific error, but I suspect the rewriting the argument list is probably part of our efforts in manual tuning of the minified code itself when we know a missing argument will be safe. Hype runtime is highly optimized for minification and already uses the Google Closure Compiler's highest setting which I would guess is still vastly superior to Babel's minifier. You shouldn't re-minify the code.

Should you ever want to export with unminified code (for the runtime and data+loader), you can use this terminal command:

defaults write com.tumult.Hype4 UseFullHypeJSTemplate -bool YES

and reset back via:

defaults delete com.tumult.Hype4 UseFullHypeJSTemplate

We won't be open-sourcing the runtime since managing open source contributions competing with goals of the application will lead to too much conflict, but I have no problem if folks want to look under-the-hood. While I enjoy a good hack, please note that modifications are entirely unsupported by Tumult.

Hopefully that gives a bit more of a peek; you will likely find that being able to do state preservation/restoration isn't something that would be a small change in the Runtime. We definitely know of the popularity of React/Vue and have your feedback on our Radar. Thanks!

2 Likes

Because safely embedding random HTML is hard :slight_smile:

I didn't try it, because it would still require me to do a bunch of work to get around the bundling, and IIRC dynamically resizing iframes are hard.

Right, that's not a problem, you can easily create a div in React so that won't be touched afterwards, but it can of course be removed and Hype should not crash after that happens, just rebuild.

Ideally, you'd call HYPE.animate(domElement, animation) and that could return a teardown function, or you could call HYPE.stop(domElement).

I now have the full code, which is easier to work with. I see the current library doesn't keep track of document listeners and timers, so that will cause leaks.

I'm not worried about state preservation, if you unmount the animation it should just start from scratch next time.

In any case I see I will mostly need to adjust the loader template.

I think this is what I need to do:

  • Allow passing a DOM node directly
  • Make it not crash on subsequent calls when the DOM node disappears
  • Keep track of listeners; add unload function
  • Make it possible to use bundled resource paths
  • Make a React wrapper component that handles the loading and wrapping

Things I hope you'll do after that turns out to work:

  • an extra exported .json file with all the data for the loader to work
  • put all the assets in a separate dir so bundlers can bundle just those

I'll try to make some minimal changes to make it work and keep you posted.

4 Likes

:partying_face:

It has been a while since I've looked building react apps/bundling, but note that Hype does have a hook to change resource URLs at runtime, if that helps.

Basic usage (global):

<script>

  function myCallback(hypeDocument, element, event) {
     var newURL = event.url; // do modifications
     return newURL;
  }

  if("HYPE_eventListeners" in window === false) {
    window.HYPE_eventListeners = Array();
  }
  window.HYPE_eventListeners.push({"type":"HypeResourceLoad", "callback":myCallback});

 </script>

That said, Hype uses relative paths to a .hyperesources folder, so you could always just stick the whole Hype project somewhere on the server outside of the react files and access that via a full URL in an iframe. Then you would need to change nothing.

As far as dynamic resizing of an iframe inside React, I can only say that I have not heard of any issues of this. I'm assuming they are using a specific size or 100%/100% width/height to fit the container.

I highly recommend trying an iframe approach ahead of hacking Hype's runtime.

Removal is the problem. Note also that Hype only builds its DOM once on its initial load. So a hack would probably involve copying the main container DOM tree outside of the react page and then move it back in (or get Hype to do the full rebuild).

As an elaboration, Hype's animations are not based on elements but on timelines. Hype keeps track of active timelines which then direct elements on what to do.

If you don't care about state, the easiest approach may be to jump to an empty scene in the document. If you don't use persistent symbols or flexible layout, this will probably remove nearly all timers/listeners.

Update: Thank you for your help. I did end up doing it with an iframe; doing it properly was just taking too long. I'd like to also use bundled resources but I can't do that across an iframe boundary because the answers would be asynchronous. (unless I somehow get the list of bundled assets into the iframe which is also kinda hacky)

@jonathan : in the Hype library, at one point there's a var arguments = .... Please rename this to var args, assigning to arguments is incorrect javascript, even if you put var in front. The minimizer also can't minimize that name. Furthermore, the generated javascript is not properly minimized, there are several if (false)... blocks that arent' removed.

2 Likes

I'm glad you were able to go with the iframe method.

Good find, thanks.

I'm not sure what you're referring to here, unless you mean what would get exported as a if(false == false) { line in the document loader file. This clearly evaluates to true in the common export case and the code is used. This is actually a bit different in the template document Hype works against; the code is: if("${unquote inlineHypeJS}" == false) { and it gets substituted before export. Keeping it is done for our code convenience, knowing that it does tradeoff a few bytes in a minimized form. We were able to get rid of 1 of the 2 of these checks in the upcoming major version of Hype.

If you're referring to something else please send me the line numbers and file you are working with. Thanks!

It's a pity that you guys aren't open-sourcing the runtime. As a full stack dev, I've tried various animation frameworks and editors in the past and hand-coded a few, from flash to new React libs, and I can say it has never been this easy, with the Hype editor you've struck a fine balance between keeping it simple and powerful enough to make excellent animations in a short time. I've been able to create more refined animations in much less time than ever!

However, opening up the runtime will result in fine people building wrappers for various frameworks and finding many the kinks for you, which will be a massive benefit to the hype community.

Runtime can be found in the resource folder of the application and you can read all about some knots and bolts of Hype here:

Not sure why you need it open source but it’s there to be studied. Modifications as in all software would lead to a branch that you would then need to re-edit on each new release of Hype. But that is a problem every software would have under most licenses. If a modification doesn’t break existing animation And functionality while integrating new frameworks Tumult might consider it. I did a fair amount of tweaking in my projects “Exportscript playground” and the unreleased “Exportmagic”. But it’s done on the fly like a live patch. That way I can keep reapplying stuff while staying up-to-date on the runtimes.

If you want to detach and reattach different animations you might consider the following approach and use iFrames to isolate Hype animations and use an messaging channel with hooks to trigger commands.

Thanks for your thoughts - open sourcing the runtime isn't something we're fundamentally opposed to; the current decision is more a matter of managing engineering tradeoffs, support costs, and advantages of tight coupling with Hype's editor.

While the unminified source included in the Hype4.app/Contents/Resources/ folder is built in such a way that isn't super easy to work with, we don't have any problem if folks tinker with it as long as you realize this is officially unsupported and the runtime could drastically change between versions :slight_smile:.