The player keeps a display list: objects at depths, each a UI16 (higher depths are drawn on top), with at most one object at a depth. The control tags of each frame change the list, and ShowFrame draws it. These tags are the same in every SWF 6 and later movie, so in every ZWS movie; there they sit in the decompressed data. Offsets in the tables are from the start of each tag’s body.
ShowFrame (1)
No body. Draws the display list as the tags so far have left it, and starts the next frame. The main timeline has as many ShowFrame tags as the header’s FrameCount.
PlaceObject (4)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | UI16 | CharacterId | The character to place |
| 2 | 2 | UI16 | Depth | Where to place it |
| 4 | … | MATRIX | Matrix | Its position, scale and rotation |
| … | … | CXFORM | ColorTransform | Optional: present if bytes remain in the tag |
The SWF 1 form, always a new object. Later movies use PlaceObject2.
PlaceObject2 (26)
Places a new object, or changes or replaces the one at a depth. A flags byte comes first, read most significant bit first:
| Bit | Value | Name | Meaning |
|---|---|---|---|
| 7 | 0x80 | PlaceFlagHasClipActions | CLIPACTIONS follow (SWF 5) |
| 6 | 0x40 | PlaceFlagHasClipDepth | ClipDepth follows |
| 5 | 0x20 | PlaceFlagHasName | Name follows |
| 4 | 0x10 | PlaceFlagHasRatio | Ratio follows |
| 3 | 0x08 | PlaceFlagHasColorTransform | ColorTransform follows |
| 2 | 0x04 | PlaceFlagHasMatrix | Matrix follows |
| 1 | 0x02 | PlaceFlagHasCharacter | CharacterId follows |
| 0 | 0x01 | PlaceFlagMove | Change the object already at the depth |
Then, in this order, each only when its flag is set:
| Type | Name | Description |
|---|---|---|
| UI16 | Depth | Always present |
| UI16 | CharacterId | The character to place |
| MATRIX | Matrix | Position, scale, rotation |
| CXFORMWITHALPHA | ColorTransform | Colour transform with alpha |
| UI16 | Ratio | For a morph shape, its position from 0 to 65,535; for a video, the frame |
| STRING | Name | The instance name, used by ActionScript |
| UI16 | ClipDepth | This object is a mask for every depth above it up to ClipDepth |
| CLIPACTIONS | ClipActions | Event handlers for a sprite |
- Move 0 with a character: place a new object; the depth should be empty.
- Move 1 without a character: change the object at the depth, only in the fields given.
- Move 1 with a character: replace the object’s character, keeping its other properties unless they are given.
PlaceObject3 (70)
SWF 8. PlaceObject2’s flags byte, then a second flags byte, most significant bit first:
| Bit | Value | Name | Meaning |
|---|---|---|---|
| 7 | 0x80 | Reserved | 0 |
| 6 | 0x40 | PlaceFlagOpaqueBackground | BackgroundColor follows |
| 5 | 0x20 | PlaceFlagHasVisible | Visible follows |
| 4 | 0x10 | PlaceFlagHasImage | With HasCharacter, makes ClassName follow (see below) |
| 3 | 0x08 | PlaceFlagHasClassName | ClassName follows |
| 2 | 0x04 | PlaceFlagHasCacheAsBitmap | BitmapCache follows |
| 1 | 0x02 | PlaceFlagHasBlendMode | BlendMode follows |
| 0 | 0x01 | PlaceFlagHasFilterList | SurfaceFilterList follows |
The SWF 10 specification had three reserved bits where SWF 19 has Reserved, OpaqueBackground and HasVisible, which came with Flash Player 11. The fields follow in this order, each only when flagged:
| Type | Name | Description |
|---|---|---|
| UI16 | Depth | Always present |
| STRING | ClassName | If HasClassName, or HasImage and HasCharacter: an ActionScript 3 class to instantiate |
| UI16 | CharacterId | As in PlaceObject2 |
| MATRIX | Matrix | |
| CXFORMWITHALPHA | ColorTransform | |
| UI16 | Ratio | |
| STRING | Name | |
| UI16 | ClipDepth | |
| FILTERLIST | SurfaceFilterList | Filters, if HasFilterList |
| UI8 | BlendMode | If HasBlendMode; values below |
| UI8 | BitmapCache | If HasCacheAsBitmap; 0 off |
| UI8 | Visible | If HasVisible; 0 hidden |
| RGBA | BackgroundColor | If OpaqueBackground |
| CLIPACTIONS | ClipActions | If HasClipActions |
RemoveObject (5)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | UI16 | CharacterId | The character to remove |
| 2 | 2 | UI16 | Depth | Its depth |
RemoveObject2 (28)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | UI16 | Depth | Removes whatever is at this depth |
FrameLabel (43)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | … | STRING | Name | The label of the current frame |
| … | 1 | UI8 | NamedAnchorFlag | Optional (SWF 6): 1 makes the label a named anchor that the browser’s Back button can reach |
DefineSprite (39)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | UI16 | SpriteID | The character ID |
| 2 | 2 | UI16 | FrameCount | The frames in the sprite |
| 4 | … | tags | ControlTags | A tag run of its own, ending with End |
A sprite is a movie clip: it plays its own timeline, independently of the one it is placed on. Only control tags may be inside it; the definitions it uses are in the main timeline.
DefineScalingGrid (78)
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | UI16 | CharacterId | A sprite or button |
| 2 | … | RECT | Splitter | The centre of the 9-slice grid: the corners outside it keep their size when the object is scaled |
DefineSceneAndFrameLabelData (86)
| Type | Name | Description |
|---|---|---|
| EncodedU32 | SceneCount | The number of scenes |
| SceneCount × (EncodedU32, STRING) | FrameOffset, Name | The frame each scene starts at, from 0, and its name |
| EncodedU32 | FrameLabelCount | The number of frame labels |
| FrameLabelCount × (EncodedU32, STRING) | FrameNum, FrameLabel | A frame, from 0, and its label |
SWF 9. The scenes and frame labels of the main timeline in one tag.
Clip actions (CLIPACTIONS)
Event handlers on a placed sprite, from onClipEvent(…) and
on(…) in ActionScript 1 and 2:
| Type | Name | Description |
|---|---|---|
| UI16 | Reserved | 0 |
| CLIPEVENTFLAGS | AllEventFlags | Every event any record below handles |
| CLIPACTIONRECORD[] | ClipActionRecords | One per handler |
| UI32 | ClipActionEndFlag | 0 |
A CLIPACTIONRECORD:
| Type | Name | Description |
|---|---|---|
| CLIPEVENTFLAGS | EventFlags | The events this handler runs on |
| UI32 | ActionRecordSize | The bytes of the record after this field |
| UI8 | KeyCode | Only if this record’s ClipEventKeyPress flag is set |
| ACTIONRECORD[] | Actions | AVM1 actions, ending with an End action (0) |
In a ZWS movie, as in every SWF 6 and later movie, CLIPEVENTFLAGS is 4 bytes and the end flag is a UI32. (SWF 5 had 2 bytes of flags and a UI16 end flag, but no ZWS movie is that old.) The bits, most significant first in each byte:
| Byte | Bits, high to low |
|---|---|
| 1 | KeyUp, KeyDown, MouseUp, MouseDown, MouseMove, Unload, EnterFrame, Load |
| 2 | DragOver, RollOut, RollOver, ReleaseOutside, Release, Press, Initialize, Data |
| 3 | UB[5] Reserved, Construct, KeyPress, DragOut |
| 4 | UB[8] Reserved |
Read as one little-endian UI32, the events are:
| Value | Event | Since | Value | Event | Since |
|---|---|---|---|---|---|
| 0x01 | Load | SWF 5 | 0x400 | Press | SWF 6 |
| 0x02 | EnterFrame | SWF 5 | 0x800 | Release | SWF 6 |
| 0x04 | Unload | SWF 5 | 0x1000 | ReleaseOutside | SWF 6 |
| 0x08 | MouseMove | SWF 5 | 0x2000 | RollOver | SWF 6 |
| 0x10 | MouseDown | SWF 5 | 0x4000 | RollOut | SWF 6 |
| 0x20 | MouseUp | SWF 5 | 0x8000 | DragOver | SWF 6 |
| 0x40 | KeyDown | SWF 5 | 0x10000 | DragOut | SWF 6 |
| 0x80 | KeyUp | SWF 5 | 0x20000 | KeyPress | SWF 6 |
| 0x100 | Data | SWF 6 | 0x40000 | Construct | SWF 7 |
| 0x200 | Initialize | SWF 6 |
The explorer lists each record as “on” and its events, with its actions disassembled.
Filters (FILTERLIST)
SWF 8. A UI8 NumberOfFilters, then each filter: a UI8 FilterID and its data.
| ID | Filter | Bytes | Fields |
|---|---|---|---|
| 0 | DropShadow | 23 | RGBA DropShadowColor, FIXED BlurX, FIXED BlurY, FIXED Angle (radians), FIXED Distance, FIXED8 Strength, UB[1] InnerShadow, UB[1] Knockout, UB[1] CompositeSource (always 1), UB[5] Passes |
| 1 | Blur | 9 | FIXED BlurX, FIXED BlurY, UB[5] Passes, UB[3] Reserved |
| 2 | Glow | 15 | RGBA GlowColor, FIXED BlurX, FIXED BlurY, FIXED8 Strength, UB[1] InnerGlow, UB[1] Knockout, UB[1] CompositeSource, UB[5] Passes |
| 3 | Bevel | 27 | RGBA ShadowColor, RGBA HighlightColor, FIXED BlurX, FIXED BlurY, FIXED Angle, FIXED Distance, FIXED8 Strength, UB[1] InnerShadow, UB[1] Knockout, UB[1] CompositeSource, UB[1] OnTop, UB[4] Passes |
| 4 | GradientGlow | 20 + 5n | UI8 NumColors, RGBA × n, UI8 Ratio × n, FIXED BlurX, FIXED BlurY, FIXED Angle, FIXED Distance, FIXED8 Strength, UB[1] InnerShadow, UB[1] Knockout, UB[1] CompositeSource, UB[1] OnTop, UB[4] Passes |
| 5 | Convolution | 15 + 4xy | UI8 MatrixX, UI8 MatrixY, FLOAT Divisor, FLOAT Bias, FLOAT × (MatrixX × MatrixY), RGBA DefaultColor, UB[6] Reserved, UB[1] Clamp, UB[1] PreserveAlpha |
| 6 | ColorMatrix | 80 | FLOAT × 20: a 4 × 5 matrix, row by row |
| 7 | GradientBevel | 20 + 5n | As GradientGlow |
Blend modes
SWF 8. The UI8 BlendMode of PlaceObject3 and of button records:
| Value | Mode | Value | Mode |
|---|---|---|---|
| 0 or 1 | normal | 8 | add |
| 2 | layer | 9 | subtract |
| 3 | multiply | 10 | invert |
| 4 | screen | 11 | alpha |
| 5 | lighten | 12 | erase |
| 6 | darken | 13 | overlay |
| 7 | difference | 14 | hardlight |
How the explorer draws a frame
It replays the control tags up to the frame and draws shapes, morph shapes at the placed ratio, sprites at the frame they have reached (stopping where a frame’s actions contain ActionStop), buttons in their up state, and static and edit text with embedded outlines, with matrices, colour transforms and clip-depth masks. It does not run ActionScript, so anything a script creates or moves is missing, and it does not draw filters, blend modes or video. An ActionScript 3 movie that builds its display in code therefore shows little or nothing.