tl;dr
This is no magic; some things work, some don’t:
- ActionScript code is not converted, but there's a trick to add Dart code in frame actions,
- Read ActionScript to Dart quick-start,
- Images are pretty fast,
- Filters are slow and sparsely supported,
- Vectors are slow and generate lots of code,
- You must learn new optimization tricks (see below),
- Delete all unused assets from your FLAs before publishing (see below),
- To publish an optimized Dart project for the web, use: Tools > Pub Deploy in DartEditor,
- Study the Runner demo sources.
(seriously, take the time to read what follows)
That’s the SWC workflow for HTML5!
In Flash development, the SWC workflow consists of exporting a SWC library of graphical assets from Flash Professional and linking it in an ActionScript project. This is a very popular and productive way to work as you benefit from a nice separation of design and code, and code completion for your library symbols in ActionScript IDEs.
The Toolkit for Dart brings back this comfort for HTML5 development:
- it will generate a perfectly clean, efficient, and code completion-friendly Dart library,
- you can iterate between code and design as in the SWC workflow.
Tips & tricks
- Set "Cache as Bitmap" in Flash Pro for best performance when using complex static symbols,
- Unlike in Flash, "Cache as Bitmap" creates a temporary image that doesn't automatically update,
- MovieClips do not play when they are cached or not attached on the stage.
- Don't break text appart and use web fonts (no support for font embedding).
- PNGs are automatically combined into atlases, unless they are too large or contain "@1x" in their name (see toolkit panel settings),
- Images ending with @1x.png are automatically substitued by @2x.png when the canvas is high-dpi,
- For mobile you may want to disable the high-dpi canvas:
if (Stage.isMobile) Stage.autoHighDpi = false;
before creating the stage instance.
How does the toolkit work
The Toolkit for Dart creates a fully functional and cleanly organized Dart project, leveraging the StageXL library to reproduce the Flash runtime features inside an HTML5 Canvas object.
About the generated symbols library:
- The main timeline and symbols with a class linkage OR present on the timeline are exported as Dart classes,
- All the embedded images and sounds are exported (and preloaded) regardless of their usage,
- Exclude images from output by adding
!
at the beginning of the symbol name (ex: SomeImage -> !SomeImage),
- Sounds are always exported as MP3s, but StageXL will try loading .ogg and .wav depending on browser support,
- Lossy (non transparent) images are exported as JPEGs respecting image compression options,
- Lossless and transparent images are combined into PNG atlases (by default and when appropriate) or PNGs,
- A preloader is generated to easily preload all the images and sounds.
Supported features:
- Images,
- Shapes (static and tweened):
- all stroke styles, custom caps and joints; but all strokes are solid (no dots),
- all fill styles; but circular gradients are always circular (no ellipse),
- (nested) MovieClips and Graphics timelines, with one constraint: you should not change an instance's type (MovieClip VS Graphic) during its lifetime as different instances will be created,
- Classic tweens and motion guides,
- SimpleButtons – only with one frame per state,
- TextFields: all texts are generated as dynamic TextFields ('input' is in progress),
- Drop-shadow and Glow filters (not animated),
- Additive blend mode,
- 'visible' and 'cacheAsBitmap' display options (Properties panel),
- Single-shape masks,
- Timeline sound events,
- Timeline scripts:
- You can write Dart code on the timeline as frame actions,
- To differentiate Dart code from ActionScript, it must be enclosed in a block comment starting with
/* js
:
/* js
// user Dart code, synchronized with the symbol's timeline
gotoAndPlay("hello"); // 'this.' is implicit like in AS3
gotoAndPlay(0); // frames index start at 0
someChild.gotoAndPlay("anim"); // child instances can be targeted
*/
Geometry changes:
- Symbol instances's position (
.x
, .y
) corresponds to the transformation point in Flash Pro and can differ from the actual registration point,
- The trick is that you can modify the registration point of a symbol using the
.pivotX
/ .pivotY
properties.
MovieClip differences compared to Flash:
- Timeline frames index start at 0 instead of 1,
- MovieClip animations stop completely as soon as they are removed from the display list,
- MovieClip instances have a 'frameRate' property to change their speed independently (not recursive).
Notable UNsupported features:
- Motion tweens (as opposed to Classic tweens),
- Animated MovieClips as masks,
- Scale9grid,
- Document class, symbol base classes,
- Most filters but shadows (Canvas limitation),
- Supported filters are not animated,
- Most blend modes but additive (Canvas limitation),
- Some TextField options (Canvas limitation) and Fonts embedding,
- Synchronized sound (only events play).
The problem with filters:
- Aside from being limited to shadows (drop-shadow, glow),
- shadows affect independently each child element of a symbol;
- the solution is to enable cacheAsBitmap on the element (cf. performance considerations).
The HTML5 Canvas is quite efficient, and the generated code aims to offer a reasonable balance between readability and efficiency.
However it is important to note that what is optimal for Flash is not necessarily ideal for the toolkit output - you will have to experiment to get the best of what the toolkit can offer.
In any case, control the generated Dart library code: it’s easy to identify that a symbol with tens or thousands of shape children will be a performance (and code size) problem.
Don’t be affraid by the final JavaScript size: nowadays scripts are always served gzipped by the servers, so always evaluate the final weight after minifying and compressing your JavaScript.
Optimizing Images output:
- The images exported by the toolkit are not optimized, it is important to take care of optimizing them before deploying using tools like pngquant which can reduce a PNG's size by 50-75%.
- Don't hesitate to use lots of PNGs as those are combined into atlases (spritesheets).
- If the atlases don't look good (after quantization):
- you can reduce the maximum atlas size to create more atlases which will require less colours,
- you can exclude some PNGs from the atlas by adding
_
or =
at the beginning of the symbol name (ex: SomeImage -> _SomeImage)
Optimizing Shapes output:
- Vector shapes are exported as "scripted drawing instructions", which is considerably slower to render than what the Flash player is able to - make sure to simplify and cache shapes,
- One vector shape can be very complex but not too heavy thanks to a special "packaged" format to represent the vertices,
- However, a rich, colorful, scene with many small shapes will generate a large amount of code; "breaking apart" a vector illustration makes things worse.
- Beware of Shape Tweens: each frame will correspond to a complete new drawing.
Optimizing performance with 'cacheAsBitmap':
- You can set 'Display > Render > Cache As Bitmap' in the Properties panel for any symbol instance on a timeline,
- When cached, the symbol becomes as fast as a Bitmap to render:
- The symbol is drawn in a temporary canvas at scale 1,
- The cache never updates automatically,
- Timelines do not play,
- Transformations (scale, rotation, alpha) can be applied freely,
- If you zoom the symbol, vectors will look blurry as would be a scaled-up image.
- This cache can be set from Dart code using the .applyCache method.
- WARNING: each cached instance corresponds to a distinct Canvas object. Displaying thousands of distinct images or canvases will make the performance collapse. Instead, like in Flash, create Bitmap instances sharing the same BitmapData.
Optimizing Text:
- Do not break text appart, it generates very heavy and slow vector shapes.
- Displaying text is usually quite efficient because StageXL TextFields are always rendered in a temporary Bitmap (see notes on 'cacheAsBitmap'),
- The shortcoming of this method is that scaled-up text will look blurry. You can cheat by scaling down a text element with a larger font size.
Final optimizations for deployment:
- Delete all unused assets from your FLAs because all embedded images/sounds are exported regardless of their usage,
- Make sure PNGs are optimized for weight (the toolkit creates non-optimized PNGs),
- Generate an optimized package using: Tools > Pub Deploy in DartEditor, this will generate a /deploy directory ready to upload with minified Dart and JavaScript code.