A look at the architecture changes in Feathers 3.0.0

Over three years ago, I released Feathers 1.0, targeting Starling 1.3. Today, I release Feathers 3.0 targeting Starling 2. It’s been an amazing experience to work hard and improve an open source project every day with the enthusiastic support of both Adobe and the wonderful Starling community.

As a new major release, Feathers 3.0 gave me the opportunity to re-imagine part of the Feathers architecture, based on feedback from developers who use Feathers in their apps and from my own experiences building new components. Let me point out a few of those architecture changes and the reasons why I made them.

Shared Constants

Way back in 1.0, I should have moved shared constants into their own classes. Instead, with each new version of Feathers, duplicate constants like HORIZONTAL_ALIGN_LEFT, SCROLL_POLICY_ON, and others repeatedly appeared throughout the Feathers codebase. I now realize that a single place to find HorizontalAlign.LEFT and ScrollPolicy.ON would have been better, and this is one of the things I cleaned up in Feathers 3.0.

When I started developing these components, I defined constants on the classes that used them because it seemed very convenient. If you needed to use a constant with the Slider class, you’d find it… on the Slider class! At the time, Feathers didn’t use many subclasses, and it had only a handful of components and layouts. I didn’t fully realize that defining constants like this wouldn’t scale very well as Feathers grew much larger over time.

By the time I started developing Feathers 2.0, I got frustrated as I saw myself duplicating constants in subclasses (so that developers wouldn’t need to know the inheritance hierarchy to find them), and I sometimes forgot to do it when new constants were added to the base classes. It was clear that things were getting a little messy in ways that I did not foresee. However, I worried that making this change would be too disruptive at the time, with the big theme changes that were included in Feathers 2.0, so the constants stayed as-is.

As I started working on Feathers 3.0 this year, I decided that this change finally needed to happen. It would indeed be disruptive, but the duplication and its side effects were getting out of hand. Using shared constant classes like VerticalAlign, RelativePosition, and Direction would be way easier for me to maintain going forward with a smaller learning curve and fewer bugs. I really wish I had made this change three years ago, but if I had waited for everything to be perfect, 1.0 would never have been released.

I’ve done my best to ease the pain of this migration. The old constants still exist, and they will not be removed until at least 18 months from now or until the next major version (whichever takes longer). Take your time switching over, and don’t feel like it must happen immediately when you upgrade. Be sure to try out the regular expressions in the Feathers 3.0 Migration Guide. You can use them with your editor’s Find/Replace feature to quickly swap out the old constants with the new. I used them on the example themes, and it was so much faster than doing the replacements manually.

saveMeasurements()

When a Feathers component’s width or height is not set explicitly, it needs to calculate appropriate dimensions during validation. Usually, this calculation is based on the dimensions of its skins and sub-components. Custom component developers will be familiar with the old setSizeInternal() method that was used to commit the calculated dimensions. This method has been deprecated and replaced with one named saveMeasurements() that accepts width and height the same as before, but also minimum dimensions as well.

Previously, the minWidth and minHeight properties defaulted to 0, and you could change them manually. However, in many layouts, the minimum dimensions may be used as a fallback. For instance, in a VerticalLayout where percentWidth is specified on children, their minWidth values of those children may be used as a fallback when the parent container’s width is not set. In previous versions, 0 would be used, which wasn’t always ideal.

Now, all core Feathers components calculate their minWidth and minHeight when needed. Custom component developers are encouraged to do the same.

As a bonus, this change helped me discover me some places where I could optimize Feathers by avoiding validation when it wasn’t necessary. This leaves Feathers in a better place for new, more advanced components that may be coming in future versions.

feathers-compat

As Feathers evolves, some APIs are inevitably deprecated and, eventually, removed. For instance, Feathers 3.0 includes a new class named ImageSkin that replaces an “advanced” class named SmartDisplayObjectValueSelector that was more cumbersome to use. Both optimize skinning by reusing the same display object with multiple textures, but ImageSKin does it in a better way.

It would be better if developers did not use SmartDisplayObjectValueSelector anymore, and I’d like to remove it from Feathers. However, existing code doesn’t rewrite itself, so developers may want to continue using this class for a while and still benefit from the bug fixes in Feathers 3.0. That’s where feathers-compat comes into play. Classes like SmartDisplayObjectValueSelector can be moved into feathers-compat so that they’re still available, if needed.

If you’re upgrading an app built with an earlier version of Feathers, and you find that some classes are missing, be sure to check if they’re included in feathers-compat.

New components on the way!

Feathers now has a stronger foundation that has been re-enforced with these architecture improvements (not just in Feathers, but in Starling too!). Starting with version 3.1 and beyond, I can start adding new and more advanced components. Stay tuned for news on what I have planned!

Also, thank you again to the community for your support, bug reports, and feedback. With your help, Feathers is better than it ever could have been if I were developing it alone. Happy coding!

Introducing NextGen ActionScript

While many creative developers thrived during the best years of Flash, plugins on the web have fallen out of favor. To continue building immersive experiences in the browser, you need to start migrating to open web standards, if you haven’t already. JavaScript is alright for little prototypes and smaller projects, but for the kind of projects that we build, it really doesn’t compare to a language like ActionScript.

What if you could continue using ActionScript on the web, but without a plugin? What if you could use JS libraries like CreateJS and Pixi.js with ActionScript? Libraries that have familiar APIs inspired by years of working with Adobe Flash Player. I don’t think developers need to start from scratch. We should embrace the open web on our own terms. We’ve heard so many claims that Flash Player is bad, but we know better. We don’t need to abandon the parts that work so well. The ActionScript language especially, but also the great display list APIs and vector drawing capabilities that we came to love so much.

NextGen ActionScript logo

Today, I’m happy to introduce my new website, NextGen ActionScript. In the first tutorial I’ve written there, I teach you how to transpile ActionScript to JavaScript using Apache FlexJS. This tutorial shows you how to integrate with an HTML page natively, by calling DOM APIs with full compile-time type checking. From there, we’re just a step away from integrating with JavaScript libraries like jQuery, CreateJS, Pixi.js, three.js and more!

I also released a new command line utility named dts2as. The TypeScript community has put a ton of effort into adding type annotations to thousands of JavaScript libraries. As we begin transpiling ActionScript, we should be able to benefit from those same resources. The dts2as utility reads a TypeScript d.ts file and uses it to generate a SWC file for a JavaScript library. Pass this SWC file to the Apache FlexJS transpiler or an IDE like Flash Builder or IntelliJ IDEA, and it’ll be as if that library were written in ActionScript. The compiler will check for errors and you’ll get code hints to speed up your development. For more details, read my second tutorial on NextGen ActionScript, Introduction to dts2as: Using TypeScript definitions with ActionScript.

Patreon logo

I’m working on many more articles and tutorials (including videos!), and I’m adding new capabilities to the dts2as utility. I’m also watching out for additional ways that new open source tools can improve the workflow with transpiled ActionScript. If you’d love to learn more about how you can keep ActionScript in your workflow (or bring it back!), please support me by becoming a patron. Patreon follows a slightly different model than sites like Kickstarter. Instead of a one-time pledge, Patreon is about more long-term, sustainable funding with small, monthly donations. You’ll get frequent updates about new tutorials and tools as I work on them, and I hope to release some special patron-only exclusives too! It’s easy to sign up and you can cancel at any time. Pledge any amount that you prefer, even as little as a dollar.

Support Josh and the next generation of ActionScript on Patreon

Thank you so much, and happy coding!

Feathers MXML internals: abstracting away Starling initialization

In Starling projects, we need a startup class that extends flash.display.Sprite or flash.display.MovieClip. In this class, we create a starling.core.Starling instance, and we set up behavior for things like resizing the view port and pausing our app or game when it goes into the background. For many projects, this class looks mostly the same. When I create a new project, I usually just copy the startup class from an existing project and modify it to pass in a different Starling root class. It would be ideal if I could simply abstract this bootstrap code away instead.

Flex applications require a significant amount of bootstrapping code too. We don’t deal with any of it, though, because the Flex SDK compiler abstracts much of it away. We can simply create a simple MXML file extending spark.components.Application:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:s="library://ns.adobe.com/flex/spark">
</s:Application>

However, behind the scenes, a Flex SWF starts up with an mx.managers.SystemManager instance as the root display object. The spark.components.Application instance isn’t the root. It’s a child. Once the SWF fully loads and the Flex framework is ready, the SystemManager instantiates the Application and adds it to the display list.

You don’t need to worry about this bootstrapping code in Flex because the spark.components.Application class defines the following metadata:

[Frame(factoryClass="mx.managers.SystemManager")]

As long as you subclass Application this metadata will tell the compiler that your class should be included on the second frame of the SWF, and the class defined in the factoryClass should be the root display object instantiated when the SWF starts up. Once the first frame loads, the SystemManager can display a preloader while the second frame is loading. When the second frame is ready, the SystemManager instantiates the Application and adds it to the display list.

[Frame] metadata isn’t restricted to Flex applications. An ActionScript project built with the Flex SDK compiler may use [Frame] metadata too. In fact, some developers may have already used this metadata with Starling projects to create a preloader for SWFs that run in a web browser.

While it isn’t a strict requirement for supporting MXML in Feathers, I want the new project experience to be as simple Flex’s. We shouldn’t need to manually instantiate Starling and set up code to resize the view port and things. It should be part of some hidden bootstrap code. A new Feathers MXML application should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<feathers:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:feathers="library://ns.feathersui.com/mxml">
</feathers:Application>

The upcoming Feathers MXML SDK will include a feathers.core.Application class that takes advantage of [Frame] metadata.

package feathers.core
{
	import feathers.controls.LayoutGroup;

	[Frame(factoryClass="feathers.core.StarlingBootstrap")]

	public class Application extends LayoutGroup
	{
		public function Application()
		{
			super();
			this.autoSizeMode = LayoutGroup.AUTO_SIZE_MODE_STAGE;
		}
	}
}

All the bootstrapping happens behind the scenes in this feathers.core.StarlingBootstrap class, which serves a similar purpose as the Flex SystemManager. However, instead of initializing the Flex framework, it sets up Starling instead. It passes our subclass of feathers.core.Application to Starling to use as the root class. It listens for the native stage Event.RESIZE to resize the Starling view port and stage. It looks just like any normal startup class for a Starling project. Not much different than Starling’s Scaffold_Mobile sample or the Feathers ComponentsExplorer example.

The main difference between StarlingBootstrap and other startup classes is that StarlingBootstrap must have a method named info(). The compiler generates a subclass of StarlingBootstrap and overrides info() to make it return an object with a number of properties. This object stores things like the name of the Starling root class and, optionally, a Feathers theme. You can see a slightly simplified example of this generated subclass below:

public class _MyFeathersApp_feathers_core_StarlingBootstrap
	extends feathers.core.StarlingBootstrap
{
	public function _MyFeathersApp_feathers_core_StarlingBootstrap()
	{
		super();
	}

	private var _info:Object;

	override public function info():Object
	{
		if (!_info)
		{
			_info = {
				rootClassName: "MyFeathersApp",
				themeClassName: "feathers.themes.MetalWorksDesktopTheme"
			};
		}
		return _info;
	}
}

You can see that our main class was named MyFeathersApp. A string representation is stored in the rootClassName property returned by the info() function. StarlingBootstrap uses getDefinitionByName() to access the Class:

var rootClassName:String = info()["rootClassName"];
var rootClass:Class = Class(getDefinitionByName(rootClassName));

Once it has the Class reference, StarlingBootstrap can pass it to Starling to instantiate when Stage 3D is ready. The compiler will automatically ensure that MyFeathersApp is compiled into the SWF, even though it is not strictly imported here.

Anyone will be able to read the ActionScript code that gets generated by the Feathers MXML SDK compiler. Similar to the Flex SDK, we will be able to add the -keep compiler argument to include a folder of generated ActionScript files in the same place as the compiled SWF.

Additionally, using the StarlingBootstrap class to bootstrap a Feathers MXML application won’t be strictly required. Custom [Frame] metadata may be added to any subclass of feathers.core.Application that will override its default metadata. This will let us provide a different startup experience, if needed. We might want to customize the stage size to support contentScaleFactor, for instance. Ideally, the bootstrapping mechanism should provide acceptable defaults for most projects, while keeping things as flexible as possible for more advanced requirements.