Hype Export Playground (Exportscript extentions)

So, this thread is about experimental export script additions. On the upside this approach gives you features you wished for at the cost of them maybe breaking down the line on new Hype releases. It boils down to continued maintenance if such patches are considered for prolonged projects. Although, that risk in general applies to any third-party export script (plugin or extension). It is currently and most likely will always be experimental in nature as I release this in my spare time. Hence, this thread is marked as USE AT YOUR OWN RISK.

To repeat it in the words of Tumult:

Here are the reasons why this is cool!

  • On a project basis you can add these through an export script and the rendered Hype Runtime is bundled
  • The patching takes place while your previewing and using advanced exports and retains the modification in code
  • No more manual patching of the runtime as that was the reason I wouldn't use this method until now even though it was discussed before
  • If you never redeploy and the exported Hype document (meaning open in open much later or without the proper exportscript) or the app is for only a specified timeframe or event most of the follow risks don't apply.

That said, what are the reasons it might break on Hype updates?

  • The substitution method (patching) is run on the minified JS (converted into Symbols). These likely change on new versions of the Hype Runtime and would require reevaluationin such cases. That said, I try to "hook" against the most likely stable patch anchors (substitution strings).
  • They could also be run against the full versions in a more stable fashion but that would make the runtime bigger, and we like small.

Exportscript Boilerplate:

#!/usr/bin/python

# 	HypeExportPlayground.hype-export.py
#		Sample on implementing patches
#
#		MIT License
#		Copyright (c) 2020 Max Ziebell
#

import argparse
import json
import sys
import os

def main():
	parser = argparse.ArgumentParser()
	parser.add_argument('--hype_version')
	parser.add_argument('--hype_build')

	parser.add_argument('--get_options', action='store_true')

	parser.add_argument('--modify_staging_path')
	parser.add_argument('--destination_path')
	parser.add_argument('--export_info_json_path')

	args, unknown = parser.parse_known_args()

	if args.get_options:		
		def save_options():
			return {
				"allows_export" : True,
				"allows_preview" : True,
			}
		
		options = {
			"save_options" : save_options(),
			"min_hype_build_version" : "596",
			# "max_hype_build_version" : "670",
		}
	
		exit_with_result(options)

	elif args.modify_staging_path != None:
		import os
		import string
		import fnmatch
		import re

		export_info_file = open(args.export_info_json_path)
		export_info = json.loads(export_info_file.read())
		export_info_file.close()
		
		# common file globs
		glob_hype_runtime_minified = 'HYPE-'+args.hype_build+'*.min.js'

		# common hooks
		hook_api = '.API={'
		hook_props = 'top:{HYP_r'

		# patch helper
		def read_content(filepath):
			with open(filepath) as f:
				return f.read()

		def save_content(filepath, content):
			with open(filepath, "w") as f:
				f.write(content)

		def patch_pre_hook(hook, insert, filePattern):
			patch(hook, hook+insert, filePattern)

		def patch_post_hook(hook, insert, filePattern):
			patch(hook, insert+hook, filePattern)
			
		def patch(find, replace, filePattern):
			for path, dirs, files in os.walk(os.path.abspath(args.modify_staging_path)):
				for filename in fnmatch.filter(files, filePattern):
					filepath = os.path.join(path, filename)
					s = read_content(filepath)
					s = s.replace(find, replace)
					save_content(filepath,s)

		def read_runtime_content():
			for path, dirs, files in os.walk(os.path.abspath(args.modify_staging_path)):
				for filename in fnmatch.filter(files, glob_hype_runtime_minified):
					return read_content(os.path.join(path, filename))
					
		runtime = read_runtime_content()
		
		# ADD PATCHES BELOW HERE


		import shutil
		shutil.rmtree(args.destination_path, ignore_errors=True)
		shutil.move(args.modify_staging_path, args.destination_path)

		exit_with_result(True)

# UTILITIES

# communicate info back to Hype
def exit_with_result(result):
	import sys
	print "===================="
	print json.dumps({"result" : result})
	sys.exit(0)


if __name__ == "__main__":
	main()

Here are some nice little snippets for the ADD PATCHES BELOW HERE spot:


showSceneByIndex

Extend the API with showSceneByIndex. It's like showSceneNamed but allows adressing the scene by index (starting at 0).

		# add showSceneByIndex
		showSceneContainer_minified = re.search('showNextScene:function\(\w,\w\){(\w+)', runtime).group(1)
		patch_pre_hook(hook_api, 'showSceneByIndex:'+showSceneContainer_minified+',', glob_hype_runtime_minified)

Enable calls like the following example:

hypeDocument.showSceneByIndex(2);

rotateY and rotateX properties

Adds these two properties to the properties you can then address using the API with setElementProperty.

		# add missing rotation properties to API
		patch_post_hook(hook_props, 'rotateX:{HYP_r:"bR",HYP_s:0},rotateY:{HYP_r:"aY",HYP_s:0},', glob_hype_runtime_minified)

Enable calls like the following examples:

hypeDocument.setElementProperty(testElm, 'rotateY', 45, 1.0, 'easeinout');
hypeDocument.setElementProperty(testElm, 'rotateX', 45, 1.0, 'easeinout');

rotatePath property

Adds a getter property so you can get the current rotation when using a motion path using the API with getElementProperty. This is useful because the runtime manages rotationZ and the motionPathRotation we are exposing here as rotatePath separately and only the combined result is found in the outputted CSS.

		# add missing path rotation property to API (motionPathRotation)
		patch_post_hook(hook_props, 'rotatePath:{HYP_r:"bO",HYP_s:0},', glob_hype_runtime_minified)

Enable calls like the following example (read-only property):

hypeDocument.getElementProperty(testElm, 'rotatePath');

You can download the Python file and a test here:

3 Likes

↑ look at project

  • [UPDATE] boiler plate with dedicated patch method
  • [UPDATE] boiler plate with variables for globs
  • [RELEASE] test file for current patches

This allows to use a dedicated patch method instead of a generic search & replace

… a little hackish – but good fun.
Thanks for sharing!

1 Like

I would recommend setting a max_hype_build_version as well.

1 Like

↑ look at project

  • [FIX] hooks are backwards compatible until 598 now!
  • [UPDATE] dynamic current minified symbols using regex

This is a stability update

1 Like

↑ look at project

  • [ADDED] rotatePath patch

Should be much more stable now. Tested the patching mechanism against runtimes back to 598

I put it in now but commented it out until I got an update channel running.

1 Like

Yes, great solution!

Future Updates on this playground thread: I may change the boilerplate from time to time and probably add some features other than patching including some samples but I won’t update this thread with individual patches anymore. This didn’t work out for the initial extensions thread as it lead to a fragmented discovery experience. Apart, from that, the thread and included code and download in my opinion sufficiently demonstrate how to use and write extensions using an export script and hence accomplishes my goal to share that knowledge. That said, I am still working on an export script but it will be a single bundle containing useful stuff.

1 Like

@MaxZieb can you recommend a good resource for learning some basic Python (as it applies for export scripts)? I’ve been working really hard to get my employer to ditch Adobe Animate for Hype and I’d love to start writing custom export scripts to demonstrate how they can streamline our workflow.

1 Like

Thanks for the support!

The internet. I am currently writing occasionally Python and it is a beautiful language. I am learning while doing and using stack overflow, google and the official docs: https://docs.python.org/2/index.html

I was doing more Python 2.7 as it comes default with my macOS version and I want to avoid people installing a newer version.

Still working on Hype ExportMagic to help with export scripts but currently development stalled. Continues whenever I have some spare time And feel like dabbling with Python.

1 Like

I just remembered a tweet about some Python books and lessons currently on Humble bundle. Not sure about the quality but it’s not expensive

https://www.humblebundle.com/books/technology-essentials-for-business-manning-publications-books

Then there is the dev topic channel for Python:

Arindam Dawn is currently running a 30 days of Python challenge.

1 Like

There is a new bundle on Humble bundle concerning Python :snake:

2 Likes