Parsing AEP Files

AfterEffects Project files are the proprietary file format used by Adobe AfterEffects.

It's a binary format based on the RIFX container format.

The structure resembles that of a Lottie JSON exported from AE.

RIFF

A RIFF is composed of "chunks" with the following format

Field Size Description
Header 4 ASCII name describing the type of the chunk
Size 4 uint32 size of the data section
Data Size Data within the chunk

RIFX is an extension of the RIFF format, the difference being RIFX uses big-endian notation for storing numbers.

A RIFF file will be structured in the same way as a chunk:

Field Size Description
Header 4 RIFF or RIFX
Size 4 uint32 size of the chunk
Format 4 Format Identifier
Chunks * Rest of the chunks

AEP-Specific Parsing

It should always be RIFX format (big endian). The format identifier for AEP is Egg!.

When parsing the RIFF structure, keep in mind the following chunks will contain other chunks:

And that LIST btdk contains data in a different format, and it should not be parsed as a RIFF LIST.

At the end of the RIFF data, the AEP file has some XML-encoded metadata.

Basic Types

Type Size Description
id 4 ASCII-encoded chunk identifier
uint16 2 Unsigned integer
uint32 4 Unsigned integer
sint16 2 Twos-complement signed integer
float32 4 IEEE float
float64 8 IEEE float
string * Text, usually utf-8 encoded
string0 * NUL terminated string, note that you might find junk data after the NUL (This can be caused by renaming something to a shorter name)
bytes * Unformatted / unknown data

Time

Time values are stored as uint16. they are scaled by a factor you can find in cdta.

To get the actual value in frames you need to do the following:

time_frames = time_value / cdta.time_scale

Additionally, layers specify a start time, which shifts all the time values by a fixed amount.

If you are within a layer the expression looks like this:

time_frames = (time_value + ldta.start_time) / (cdta.time_scale)

Flags

Flags is byte data, that will be specified using two integers: byte and bit index.

You'll get the value of the flag you'll need to do the following:

flag = (flags[byte] & (1 << bit)) != 0

AfterEffects Logic

Project Structure

The contents of the project are in the top-level LIST Fold.

Inside here you'll find (among other things) LIST Item chunks, they all contain an idta which tells you how to interpret the item and its ID.

Compositions

idta has type of 4. You need to know which composition to extract as a lottie corresponds to a specific comp (with other compositions showing as assets for precomps).

The name of the composition is in the first Utf8 chunk.

Its properties are in cdta.

Then look for LIST Layr to parse layers.

Folders

idta type 1. These contain additional items inside them.

The name of the folder is in the first Utf8 chunk.

Look for a LIST Sfdr and iterate through it for the child items.

Assets

idta type 7. These can have different kinds of contents.

LIST Pin will contain the asset data:

Look for sspc to get the size for visual assets.

The type of asset is defined in the first 4 bytes of opti.

Solids

For some the Item has an Utf8 but it seems to always be empty need to find the name from opti.

Files

The Uft8 in Item only has a value if the user has set an explicit value for the name.

The file path is in LIST Pin > LIST Als2 > alas. Interpret it as JSON and get fullpath.

the first 4 bytes of opti will change based on the file format.

There will also be a LIST CLRS with some Utf8, in there there's some JSON with base64-encoded ICC color profiles.

Layers

Layers are defined in LIST Layr.

There are different types of layers:

Shape Layer

For shapes look for the match name ADBE Root Vectors Group.

Camera Layer

For camera settings look for the match name ADBE Camera Options Group.

Text Layer

For text contents look for the match name ADBE Text Properties.

Asset Layer

(Also known as AVLayer in AE) They have a non-zero Source ID in ldta.

Image layers and similar will point to an appropriate asset.

Several layer types point to a solid asset, you need to check the layer attributes to distinguish between them:

  • Solid layers
  • Null layers
  • Adjustment layers

Light Layer

For light settings look for the match name ADBE Light Options Group.

Property Groups

Most objects are described as a property groups.

These have the following structure:

Then follows a list of properties, all introduced by their match name (tdmn).

After a match name, you'll find the data for the property, which might be an actual propert (see the section below), other groups, or layer effects.

This structure is used both for objects (that have a fixed set of properties) and groups/collections whose contents might vary.

For objects with fixed properties you will not find duplicate match names but you might find duplicates within collections.

Properties

Properties, like objects are introduced by their match name, the chunks following that depends on the type of property.

The core of a property is defined in LIST tdbs with the following structure:

  • LIST tdbs: Property definition
    • tdb4: Tells you the type, number of components, whether it's animated
    • cdat: Value (if not animated)
    • Utf8: Optional expression
    • LIST list: Keyframes (if animated)
      • lhd3: Tells you the number of keyframes
      • ldat: Keyframe data and values

For simple properties, with vector or scalar values, you get the structure above.

For more complex properties, you get an outer object that contains that data as well as a list of values. You'll get the value for the keyframes (or the static value) from that list.

Color properties are laid out as ARGB floats in [0, 255].

Note that the keyframe structure in ldat changes based on the info found in tdb4.

Shape

Gradient Colors

Orientation

Marker

Text Document

Expressions

Bodymovin modifies expressions when converting into lottie, if you add expressions but fail to convert them, the animation might not play properly.

Assets

Image

Defined within LIST Item, it will have idta with type 7.

Within that there's a LIST Pin, containing the following:

LIST Als2 with alas, which in turn has some JSON. Inside the JSON you can get fullpath.

opti: Contains the asset name.

LIST CLRS, the last Utf8 here has some JSON with a base64-encoded color profile.

Shapes

Stroke Dashes

Look for the match name ADBE Vector Stroke Dashes.

Inside of it you'll find a bunch of properties with match name ADBE Vector Stroke Dash n or ADBE Vector Stroke Gap n, where n is an ineger starting from 1.

You will also find a single ADBE Vector Stroke Offset.

They are all animatable lengths and fairly straighforward.

Note that lottie-web wants a unique "name" for these, and the file doesn't provide this but you can generate one based on the match name.

Transforms

Split Position

When a position is split the Position attribute is removed and you can get the data from Position_0 and Position_1.

For some reason Position_0 and Position_1 are present (with value 0) even when the position is not split.

Their tdsb seems to change from 1 (not split) to 3 (split).

Effects

The effects used in by the file are defined in the top-level chunk LIST EfdG, instanciations of these effects are present in the layers that use them.

  • LIST EfdG: Effect definitions
    • EfDC: Effect definition count (number of definitions)
    • LIST EfDf: Effect definition (one per effect type used in the document)
      • tdmn: Effect match name
      • LIST sspc
      • LIST parT: Effect parameters
        • parn: Number of parameters
        • tdmn: Parameter match name
        • pard: Parameter definition
        • You get a pair of tdmn and pard for each parameter
      • LIST tdgp: Contains the values of the first instance of this effect, can be ignored

Note that the first paramter in an effect should be ignored.

The effects in a later are listed under ADBE Effect Parade:

  • tdmn: Effect match name, you'll need to find the matching definition
  • LIST sspc
    • fnam > Utf8: Effect name
    • LIST parT: You might find this here as well but it isn't consistent. Refer to LIST EfdG for the definition
    • LIST tdgp: Parameter values, works like any other property list

Match Names

Follows a list of known match names grouped by object type.

For properties that specify a default value, you should assume they have the specified value if they are not present in the AEP file.

Layers

Match Name Description Default
ADBE Root Vectors Group shapes
ADBE Layer Styles styles
ADBE Transform Group ks
ADBE Layer Styles sy
ADBE Extrsn Options Group
ADBE Material Options Group
ADBE Audio Group
ADBE Layer Sets
ADBE Time Remapping tm
ADBE Effect Parade ef
ADBE Marker Markers
Match Name Description Default
ADBE Camera Options Group Camera Layer Marks a layer as a camera layer
ADBE Camera Aperture pe
ADBE Camera Zoom
Match Name Description Default
ADBE Text Properties Text Data
ADBE Text Document d
ADBE Text Path Options p
ADBE Text More Options m

Shapes

Match Name Description Default
ADBE Vector Group Group
ADBE Vector Blend Mode bm12
ADBE Vectors Group it
ADBE Vector Transform Group Transform
ADBE Vector Materials Group
Match Name Description Default
ADBE Vector Shape - Rect Rectangle
ADBE Vector Shape Direction d1
ADBE Vector Rect Position p
ADBE Vector Rect Size s
ADBE Vector Rect Roundness r
Match Name Description Default
ADBE Vector Shape - Ellipse Ellipse
ADBE Vector Shape Direction d1
ADBE Vector Ellipse Position p
ADBE Vector Ellipse Size s
Match Name Description Default
ADBE Vector Shape - Ellipse Ellipse
ADBE Vector Shape Direction d1
ADBE Vector Ellipse Position p
ADBE Vector Ellipse Size s
Match Name Description Default
ADBE Vector Shape - Star PolyStar
ADBE Vector Shape Direction d1
ADBE Vector Star Type sy1
ADBE Vector Star Points pt3
ADBE Vector Star Position p
ADBE Vector Star Rotation r
ADBE Vector Star Inner Radius ir
ADBE Vector Star Outer Radius or
ADBE Vector Star Inner Roundess is
ADBE Vector Star Outer Roundess os
Match Name Description Default
ADBE Vector Shape - Group Path
ADBE Vector Shape Direction d1
ADBE Vector Shape ks4

Shape Styles

Match Name Description Default
ADBE Vector Graphic - Fill Fill
ADBE Vector Blend Mode bm12
ADBE Vector Fill Color c5 [255, 255, 0, 0]
ADBE Vector Fill Opacity o 100
ADBE Vector Fill Rule r1 1
ADBE Vector Composite Order if 2, it should be drawn over the previous shape 1
Match Name Description Default
ADBE Vector Graphic - Stroke Stroke
ADBE Vector Blend Mode bm12
ADBE Vector Stroke Color c5 [255, 255, 255, 255, ]
ADBE Vector Stroke Opacity o 100
ADBE Vector Stroke Width w 2
ADBE Vector Stroke Line Cap lc1 1
ADBE Vector Stroke Line Join lj1 1
ADBE Vector Stroke Miter Limit ml2 4
ADBE Vector Stroke Dashes d
ADBE Vector Stroke Taper
ADBE Vector Stroke Wave
ADBE Vector Composite Order if 2, it should be drawn over the previous shape 1
Match Name Description Default
ADBE Vector Stroke Taper All properties are percentages in [0, 100]
ADBE Vector Taper Start Length
ADBE Vector Taper End Length
ADBE Vector Taper Start Width
ADBE Vector Taper End Width
ADBE Vector Taper Start Ease
ADBE Vector Taper End Ease
Match Name Description Default
ADBE Vector Stroke Wave
ADBE Vector Taper Wave Amount
ADBE Vector Taper Wave Units 1 for pixels, 2 for cycles
ADBE Vector Taper Wavelength
ADBE Vector Taper Wave Phase
Match Name Description Default
ADBE Vector Graphic - G-Fill Gradient Fill
ADBE Vector Blend Mode bm12
ADBE Vector Grad Start Pt s
ADBE Vector Grad End Pt e [100, 0]
ADBE Vector Grad HiLite Length h
ADBE Vector Grad HiLite Angle a
ADBE Vector Grad Colors g6
ADBE Vector Fill Opacity o 100
ADBE Vector Fill Rule r1 1
ADBE Vector Composite Order if 2, it should be drawn over the previous shape 1
Match Name Description Default
ADBE Vector Graphic - G-Stroke Gradient Stroke
ADBE Vector Blend Mode bm12
ADBE Vector Grad Type t
ADBE Vector Grad Start Pt s
ADBE Vector Grad End Pt e
ADBE Vector Grad HiLite Length h
ADBE Vector Grad HiLite Angle a
ADBE Vector Grad Colors g6
ADBE Vector Stroke Opacity o 100
ADBE Vector Stroke Width w 2
ADBE Vector Stroke Line Cap lc1 1
ADBE Vector Stroke Line Join lj1 1
ADBE Vector Stroke Miter Limit ml2
ADBE Vector Stroke Dashes d
ADBE Vector Stroke Taper
ADBE Vector Stroke Wave
ADBE Vector Composite Order if 2, it should be drawn over the previous shape 1

Shape Modifiers

Match Name Description Default
ADBE Vector Filter - Merge Merge
ADBE Vector Merge Type mm
Match Name Description Default
ADBE Vector Filter - Offset Offset Path
ADBE Vector Offset Amount a
ADBE Vector Offset Line Join lj1
ADBE Vector Offset Miter Limit ml
Match Name Description Default
ADBE Vector Filter - PB Pucker Bloat
ADBE Vector PuckerBloat Amount a
Match Name Description Default
ADBE Vector Filter - Repeater Repeater
ADBE Vector Repeater Transform tr
ADBE Vector Repeater Copies c3
ADBE Vector Repeater Offset o
ADBE Vector Repeater Order m1
Match Name Description Default
ADBE Vector Filter - RC Rounded Corners
ADBE Vector RoundCorner Radius r
Match Name Description Default
ADBE Vector Filter - Trim Trim
ADBE Vector Trim Start s
ADBE Vector Trim End e
ADBE Vector Trim Offset o
Match Name Description Default
ADBE Vector Filter - Twist Twist
ADBE Vector Twist Angle a
ADBE Vector Twist Center c
Match Name Description Default
ADBE Vector Filter - Roughen
ADBE Vector Roughen Size
ADBE Vector Roughen Detail
ADBE Vector Roughen Points
ADBE Vector Temporal Freq
ADBE Vector Correlation
ADBE Vector Temporal Phase
ADBE Vector Spatial Phase
ADBE Vector Random Seed
Match Name Description Default
ADBE Vector Filter - Wiggler
ADBE Vector Xform Temporal Freq
ADBE Vector Correlation
ADBE Vector Temporal Phase
ADBE Vector Spatial Phase
ADBE Vector Random Seed
ADBE Vector Wiggler Transform
Match Name Description Default
ADBE Vector Filter - Zigzag Zig Zag
ADBE Vector Zigzag Size s
ADBE Vector Zigzag Detail r
ADBE Vector Zigzag Points pt3

Transforms

Match Name Description Default
ADBE Transform Group Transform
ADBE Anchor Point a [0, 0]
ADBE Position p Half of the comp size
ADBE Position_0 Split position X
ADBE Position_1 Split position Y
ADBE Position_2 Split position Z
ADBE Scale s7 [1, 1]
ADBE Orientation or
ADBE Rotate X rx
ADBE Rotate Y ry
ADBE Rotate Z rzor just normal rotation 0
ADBE Opacity o7 1
ADBE Envir Appear in Reflect Single float, probably a boolean?
Match Name Description Default
ADBE Vector Transform Group Transform Shape
ADBE Vector Anchor Point a
ADBE Vector Anchor a probably an outdated name
ADBE Vector Position p
ADBE Vector Scale s
ADBE Vector Rotate X rx
ADBE Vector Rotate Y ry
ADBE Vector Rotate Z rzor just normal rotation
ADBE Vector Rotation r
ADBE Vector Group Opacity o 1
Match Name Description Default
ADBE Vector Repeater Transform Repeater Transform
ADBE Vector Repeater Anchor Point a
ADBE Vector Repeater Position p
ADBE Vector Repeater Scale s7
ADBE Vector Repeater Rotation r
ADBE Vector Repeater Start Opacity so7 1
ADBE Vector Repeater End Opacity so7 1

Effects

Match Name Description Default
ADBE Tint Tint Effect ty=20
ADBE Fill Fill Effect ty=21
ADBE Stroke Stroke Effect ty=22
ADBE Tritone Tritone Effect ty=23
ADBE Pro Levels2 Pro Levels Effect ty=24
ADBE Drop Shadow Drop Shadow Effect ty=25
ADBE Radial Wipe Radial Wipe ty=26
ADBE Displacement Map Displacement Map Effect ty=27
ADBE Set Matte3 Set Matte Effect ty=28
ADBE Gaussian Blur 2 Gaussian Blur Effect ty=29
ADBE Twirl Twirl Effect ty=30
ADBE MESH WARP Mesh Warp Effect ty=31
ADBE Ripple Wavy Effect ty=32
ADBE Spherize Spherize Effect ty=33
ADBE FreePin3 Puppet Effect ty=34
Match Name Description Default
ADBE Effect Built In Params Marks a LIST tdgp with built-in effect properties
ADBE Effect Mask Opacity
Match Name Description Default
ADBE Paint Group Data for the paint effect
ADBE Paint Atom Contains the following properties
ADBE Paint Duration
ADBE Paint Shape
ADBE Paint Transform Same as other transform but match names starting with ADBE Paint
ADBE Paint Properties contains the following
ADBE Paint Clone Layer

Misc

Match Name Description Default
ADBE Group End Indicates the end of a LIST tdgp

Notes


  1. Enumerations needs to be converted from floats, but the values match. 

  2. Blend mode has different values than Lottie, see the section below for details. 

  3. Needs to be converted from float to int

  4. How to parse this? 

  5. Colors are defined as 4 floats (ARGB) in [0, 255]. 

  6. Colors defined as XML

  7. You need to multiply by 100 to get the lottie value. 

Enumerations

Most enumerated values are the same in Lottie and AEP, this section lists the exceptions to this

Blend Mode

Name AEP Lottie
Normal 1 0
Darken 3 4
Multiply 4 1
Color Burn 5 7
Linear Burn 6
Darker Color 7
Lighten 9 5
Screen 10 2
Color Dodge 11 6
Linear Dodge 12
Lighter Color 13
Overlay 15 3
Soft Light 16 9
Hard Light 17 8
Linear Light 18
Vivid Light 19
Pin Light 20
Hard Mix 21 16
Difference 23 10
Exclusion 24 11
Hue 26 12
Saturation 27 13
Color 28 14
Luminosity 29 15

Chunk Data

Note that chunks might have extra data after what is described here, always parse exactly as many bytes as specified in the chunk header.

LIST

This chunk is defined by the RIFF specs, its data has the following format:

Starts with an id, specifying the type of the list, then followed by sub-chunks.

The format of specific LIST types are described later in this document.

Note that the LIST btdk doesn't conform to RIFF, so take care to not read over the chunk length.

Utf8

Contains utf-8 encoded text. Sometimes it contains the string -_0_/- which (I guess) is used as a placeholder for objects lacking a name.

tdsn / fnam / pdnm

Contains a Utf8 chunk, used for object names

tdmn

Contains a NUL-terminated string (You'll need to strip excess \0) and defines a Match Name.

fdta

Folder data.

cdta

Composition data.

Field Name Size Type Description
5
Time Scale 2 uint16 How much Time values are scaled by
14
Playhead 2 Time Playhead time
6
In Time 2 Time Same as ip in Lottie
6
Out Time 2 Time Same as op in Lottie
6
Comp duration 2 Time Duration setting in AE
5
Color 3 bytes Color as 24 bit RGB
85
Width 2 uint16 Same as w in Lottie
Height 2 uint16 Same as h in Lottie
12
Framerate 2 uint16 Same as fr in Lottie

Note that End Time might have a value of FFFF, if that's the case assume it to be the same as Comp Duration.

ldta

Layer data, it seems that AE23 adds 4 extra 00 bytes at the end compared to older versions.

Field Name Size Type Description
Layer ID 4 uint32
Quality 2 uint16 0: Wireframe, 1: Draft, 2: Best
7
Start Time 2 sint16 Time offset for times withing the layer
6
In Time 2 Time Same as ip in Lottie
6
Out Time 2 Time Same as op in Lottie
6
Attributes 3 Flags
Source ID 4 uint32 Item id for the used asset
17
Label Color Index 1 uint8 Color on the timeline
2
Layer Name 32 string0 It's repeated in the Utf8 chunk right after
11
Matte Mode 1 uint8
Layer Type 1 uint8
Parent ID 4 uint32 ID of the parent layer, if any
24
Matte Layer ID 4 uint32 Id of the layer masking the current layer, if any

With the following Attributes:

  • Guide: (0, 1) Guide layers aren't rendered
  • Bicubic Sampling: (0, 6)
  • Auto Orient: (1, 0)
  • Adjustment: (1, 1) Whether it's an adjustment layer
  • Threedimensional: (1, 2)
  • Solo: (1, 3) (UI thing, only displays that layer)
  • Null: (1, 7) Whether it's a null layer
  • Visible: (2, 0)
  • Effects: (2, 2)
  • Motion Blur: (2, 3)
  • Locked: (2, 5)
  • Shy: (2, 6) (Used to hide some layers in the AE UI)
  • Conitnuosly Rasterize (vector) / Collapse Transform (comps): (2, 7)

Layer Types:

  • 0: Asset Layer
  • 1: Light Layer
  • 2: Camera Layer
  • 3: Text Layer
  • 4: Shape Layer

Label Colors:

  1. None (shows as grey)
  2. Red
  3. Yellow
  4. Aqua
  5. Pink
  6. Lavender
  7. Peach
  8. Sea Foam
  9. Blue
  10. Green
  11. Purple
  12. Orange
  13. Brown
  14. Fuchsia
  15. Cyan
  16. Sandstone
  17. Dark Green

Matte Modes:

  1. No Matte
  2. Alpha
  3. Inverted Alpha
  4. Luma
  5. Inverted Luma

idta

Item data.

Field Name Size Type Description
Type 2 uint16
14
ID 4 uint32 ID used to reference this item

The Type field above can have the following values:

  • 1: Folder
  • 4: Composition
  • 7: Footage

The last 2 bytes of this field seem to change every time you make a change.

tdb4

Property metadata.

Field Name Size Type Description
2 Always db 99?
Components 2 uint16 Number of values in a multi-dimensional
Attributes 2 Flags
1
1 Some sort of flag, it has value 03 for position properties
2
2
2 Always 0000 ?
2 2nd most significant bit always on, perhaps some kind of flag
8 float64 Most of the time 0.0001
8 float64 Most of the time 1.0, sometimes 1.777
8 float64 Always 1.0?
8 float64 Always 1.0?
8 float64 Always 1.0?
Type? 4 Flags See below
1 Seems correlated with the previous byte, it's set for 04 for enum properties
7 Bunch of 00
Animated 1 Set to 1 when animated, kinda the reverse of the Static bit in Attributes
7 Bunch of 00
4 Usually 0, probs flags
4 Mst likely flags, only last byte seems to contain data
8 float64 Always 0.0?
8 float64 Mostly 0.0, sometimes 0.333
8 float64 Always 0.0?
8 float64 Mostly 0.0, sometimes 0.333
4 Probs some flags
4 Probs some flags

Attributes:

  • Position: (1, 3). When true, this is a position property, which changes how animated values are parsed.
  • Static: (1, 0). When false, the property is animated and it will have a cdat.

Types:

  • No Value: (1, 0). Used for properties like shapes, gradients, etc, where the values are not in the keyframe.
  • Color: (3, 0). Set for color properties (they have a different keyframe format).

cdat

Property static value.

For multi-dimensional properties, you look at the number of components in tdb4 and parse that many float64, that's the value of the property.

shph

Header for bezier shape data, contained within LIST shap.

It's followed by a LIST list with bezier data.

Field Name Size Type Description
3
Attributes 1 Flags
Top Left 2 float32 Top-left corner of the shape area, relative to the layer position
Bottom Right 2 float32 Bottom-right corner of the shape area, relative to the layer position
4

Flags:

  • Open: (0, 3). When true, the shape is open (it's missing the segment connecting the last point to the first)

lhd3

Inside a LIST list, defines the data format, followed by ldat.

Field Name Size Type Description
4 Seems to always be 00 d0 0b ee
6 All 00
Count 2 uint16 Number of items
4 The last byte is the only one that changes, greatest variation is on shapes
2 All 00
Item Size 2 uint16 Size of an item in the list
3 All 00
Type? 1
4 00 00 00 01
2 All 00
2 Some kind of flags
20 All 00
Item Type Size Type
Gide 00 01 02
LItm 00 80 01
LRdr 08 c6 01
Color Kf 00 98 04
1D Kf 00 30 04
2D Kf 00 58 04
2D pos Kf 00 68 04
3D Kf 00 80 04
3D pos Kf 00 80 04
Marker Kf 00 10 04
Orientation Kf 00 50 04
No Value Kf 00 40 04

The corresponding ldat should have Item Size * Count bytes, and it's omitted if Count is 0.

ldat

Inside a LIST list, contains the list data, preceded by lhd3.

The number of element is the one defined in lhd3.

It has a different format based on certain conditions, follow some of the possible element formats.

The size of an item is found like so:

item_size = ldat_chunk_length / lhd3_count

Keyframe (common)

All keyframe items start like this:

Field Name Size Type Description
1
Time 2 Time Time of the keyframe, seems they always start from 0.
2
Attributes 1 Flags
Label Color 1 uint8 Color index, see ldta for values
Extra Attributes 1 Flags

Attributes:

  • Linear (0, 0) seems to be on then Ease is off
  • Ease (0, 1)
  • Hold (0, 2)

Extra Attributes:

Least significant 3 bits seems to always be on.

  • Continuous Bezier (0, 3)
  • Auto Bezier (0, 4)
  • Roving across time (0, 5)

Keyframe - Multi-Dimensional

Given n as the number of dimensions found in tdb4 (eg: 3 for 3D positions):

Field Name Size Type Description
Value 8* n float64[n] Value
In Speed 8* n float64[n]
In Influence 8* n float64[n]
Out Speed 8* n float64[n]
Out Influence 8* n float64[n]

Keyframe - Position

If the property is an animated position, the keyframe is formatted like so:

Field Name Size Type Description
8
8 float64
In Speed 8 float64
In Influence 8 float64
Out Speed 8 float64
Out Influence 8 float64
Value 8* n float64[n] Value
Tan In 8* n float64[n] Spatial tangents
Tan Out 8* n float64[n] Spatial tangents

Keyframe - No Value

Used for shapes and gradients (Special set in tdb4)

Field Name Size Type Description
8
8 float64
In Speed 8 float64
In Influence 8 float64
Out Speed 8 float64
Out Influence 8 float64
8

Keyframe - Color

Field Name Size Type Description
8
8 float64
In Speed 8 float64
In Influence 8 float64
Out Speed 8 float64
Out Influence 8 float64
Value 8*4 float64[4] ARGB 255
8*8 float64[8]

Shape Data

Bezier data, positions are relative to the area defined by shph.

The list is a sequence of points, appearing in this order:

  • Vertex 0
  • Out Tangent 0
  • In Tangent 1
  • Vertex 1
  • Out Tangent 1
  • ...

Note that all coordinates are relative to the area in shph but not to each other.

A coordinate of [0, 0] will correspond to the top-left corner in shph, and [1, 1] corresponds to the bottom-right.

Field Name Size Type Description
X 4 float32 X Coordinate
XY 4 float32 X Coordinate

pprf

Color profile information as ICC data.

wsnm

Worspace name.

Utf-16 encoded string, contains the name of the "workspace" (window layout in AE)

It's always followed by an Utf8 with the same content.

tdum / tduM

float64 values often found inside LIST tdbs.

In some cases they seem to indicate minimum and maximum values for that property but there are some cases in which they are both 0.0.

ppSn

Contains a float64, unknown meaning.

otda

Orientation data

Field Name Size Type Description
X 8 float64 X Coordinate
Y 8 float64 Y Coordinate
Z 8 float64 Z Coordinate

opti

Asset data, format depends on type

Field Name Size Type Description
Type 4 string Asset type

Solid

Type Soli, data for solid layers.

Field Name Size Type Description
6
Alpha 4 float32
Red 4 float32
Green 4 float32
Blue 4 float32
Name 256 string0

Color components are in [0, 1].

sspc

Footage / asset data.

Field Name Size Type Description
32
Width 2 uint16
2
Height 2 uint16

alas

JSON string containing external asset info.

Seems the first 6 bytes contain AE version information.

I haven't been able to decode it fully but here's a list of values encountered in the wild:

Version Bytes
15.0 5c 06 07 38 06 b4
16.0 5d 04 0b 00 06 eb
16.0.1 5d 04 0b 00 0e 30
16.1.2 5d 05 0b 00 96 37
16.1.3 5d 05 0b 00 9e 05
17.0 5d 09 4b 08 06 2b
17.0.4 5d 0b 0b 08 26 3b
18.2.1 5d 1b 0b 11 0e 08
18.4 5d 1d 0b 12 06 26
22.0 5d 1d 0b 70 06 6f
22.6 5d 2b 0b 33 06 3b
23.2.1 5e 03 0b 39 0e 03

EfDC

The first byte contains the number of LIST EfDf in a LIST EfdG

parn

Contains a uint64 with the number of parameters in a LIST parT.

pard

Effect parameter definition.

Field Name Size Type Description
15
Type 1 uint8 Parameter type
Name 32 string0
4
Default? 4
Last used value?

Types:

Type Name AEP Lottie Lottie Object
Layer 0 10 Effect Value Layer
Scalar 2 0 Effect Value Slider
Angle 3 1 Effect Value Angle
Boolean 4 4 Effect Value Checkbox
Color 5 2 Effect Value Color
2D 6 3 Effect Value Point
Enum 7 7 Effect Value Drop Down
Paint Group 9
Slider 10 0 Effect Value Slider
Group 13 5 Custom Effect
Unknown 15 6 Effect No Value
3D 16 3 Effect Value Point

prin

Seems to always have the same content:

4 00 bytes, the string ADBE Escher, 37 00, the string Classic 3D, 41 00, and ends with 01.

prda

Seems to always have the same content: 3 00, a 01, 8 00.

NmHd

Marker attributes

Name Size Type Description
3
Attributes 1 Flags
Duration 4 uint32 Duration in frames
4
Label Color 1 uint8 Color index, see ldta for values

Flags:

  • Protected: (0, 1) The marker signals a protected region
  • ???: (0, 2) This flags seems to always be on

tdsb

4 bytes specifying flags for a tdgp.

the least significant bit marks if an object is visible.

LIST Fold

Top level item.

LIST Item

Item, you can check its properties with idta contained inside it.

LIST Layr

Defines a layer.

Layer metadata is found in a ldta, the layer name is in a Utf8.

Go through its LIST tdgp to get shapes and transforms.

You will find the following match names within it:

  • ADBE Root Vectors Group: Contains shape data (shape layer in lottie)
  • ADBE Camera Options Group: Lottie camera layer
  • ADBE Transform Group: Layer transform
  • ADBE Layer Styles: Layer styles

LIST tdgp

Defines a list of an object. To know what type of object, you need to check the tdmn preceding this chunk.

Flags for the objects are in tdsb.

The name of the object is in tdsn > Utf8.

Then follows a sequence of properties / objects defined as such:

tdmn specifies the match name of the object, then it's followed by chunks that describe said object (usually more LISTs).

Usually the last chunk here is a tdmn with value ADBE Group End.

LIST tdbs

Defines an object's property. To know which property, you need to check the tdmn preceding this chunk.

It will contain a tdb4, and usually cdat (static) or a List list (animated).

For properties with expressions, it will have a Utf8 with the expression code.

LIST GCst

Defines a gradient.

Contains a LIST tdbs and a LIST GCky.

LIST GCky

Gradient color keyframes.

Contains a sequence of Utf8 formatted in XML with the gradient definition for each keyframe.

LIST om-s

Contains a LIST tdbs and a LIST omks to define a shape property.

LIST omks

Bezier shape data.

Contains a sequence of LIST shap with the shape data for each keyframe.

LIST shap

Contains a shph and a LIST list with the shape data.

LIST CPPl

Contains a pprf.

LIST list

For animated properties it replaces cdat.

The list header is defined in the chunk lhd3, the list data in ldat.

LIST SLay / LIST DLay / LIST CLay

They seem to be camera layers used to store internal views, not exported to lottie.

SLay (Side views?) have names like "Top" and "Front", perhaps they define 3d views.

CLay: Custom views.

DLay: Default views.

LIST SecL

Composition Markers Layer.

Contains ldta and like other layers.

in LIST tbgp look for the match name ADBE Marker, the data is in the LIST mrst.

LIST mrst

Marker property.

Contains a LIST tdbs that defines the property, which should always be animated when present.

Marker keyframe values are available in LIST mrky.

LIST mrky

Marker keyframes.

contains a LIST Nmrd for each keyframe

LIST Nmrd

Marker data

There's a NmHd with the attributes.

The marker comment is in the first Utf8

LIST otst

Orientation property.

Contains a LIST tdbs and a LIST otky to define a shape property.

LIST otky

Contains a sequence of otda with the orientation data for each keyframe.

LIST CpS2

They contain a CsCt and two Utf8, the last of which seems to contain a locale name (eg: en_US)

LIST Als2

Contains alas for external assets.

LIST Sfdr

Asset folder contents, contains several LIST Item.

LIST btdk

For some reason this doesn't conform to the RIFX specs, instead of a list its data is encoded in Carousel Object Structure (COS).

The COS format is the same used in PDF but it's extremely difficult to find detailed information on it, the best technical specs is this very old PDF 1.7 specification.

Once you parse the COS, you can find the following data:

  • 0.1.0: Array of available fonts:
    • 0.99: CoolTypeFont
    • 0.0.0: Font family (seems to have bold/italic encoded in the name)
    • 0.0.2: 0 or 1?
  • 1.1: Array of text documents (one for each keyframe) in this format:
    • 0.0: Text
    • 0.5.0: Array of paragraph styles
      • 0.0.5 Paragraph Style:
        • 0: Text align (0: left, 1: right, 2: center)
      • 1: Length (in characters) the style applies to
    • 0.6.0: Array of character styles:
      • 0.0.6: Character Style:
        • 0: Index of the font from the array of available fonts
        • 1: Font size
        • 2: Faux Bold
        • 3: Faux Italic
        • 12: 0: Normal, 1: Small caps, 2: All caps
        • 13: 0: Normal, 1: Superscript, 2: Subscript
        • 53.0.1: Fill color in ARGB [0, 1]
        • 54.0.1: Stroke color in ARGB [0, 1]
        • 57: Stroke enabled
        • 58: Stroke over fill
        • 63: Stroke width
      • 1: Length (in characters) the style applies to

LIST sspc

Effect Definiton.

The generic effect name is in fnam > Utf8.

The effect parameters are defined in LIST parT. If the effect type has already been encountered, you might not find the LIST parT here, you might need to match the name to an entry in LIST EfdG.

It finally contains a LIST tdgp where the effect properties are present like any other animated property. You can also find the name of the effect object in fnam > Utf8.

Inside there you can also find a match name with ADBE Effect Built In Params which will contain values for built-in effect parameters.

LIST parT

Effect parameters.

Contains a parn with the number of parameters, then follows a list of tdmn with the match name of the parameter followed by pard with its definition.

Enum parameters have their values in a pdnm separated by | pipes.

The first property seems to be a dummy?

LIST EfdG

Effect definitions.

This is where effect types used by the project are defined.

Basically it repeats the first instance of any effect found in the layers.

it contains a EfDC with the number of effects, and that many LIST EfDf.

LIST EfDf

Effect type definition.

Contains a tdmn with the match name of the effect and a LIST sspc.

LIST ExEn

Contains a Utf8 with the expression language (eg: javascript-1.0).

LIST PRin

Contains a prin and a prda.

LIST Pin

Asset properties.

Contains:

  • sspc with some common properties
  • Utf8 with the name (except for solids)
  • opti with asset data

Gradient XML

Gradient data seems to be stored in a convoluted XML structure.

The easiest way to describe it is as a mapping, the elements can be parsed like so:

Tag Name Logical Type Description
prop.map Top-level, just get its first child
prop.list dict Mapping of key-value pairs
prop.pair Item in prop.list
key str Property key
array list Array of values, the first item is array.type which specifies the type
int int
float float
string str

If you interpret the XML as a mapping, you can gather the following info:

{
    "Gradient Color Data":
    {
        "Alpha Stops":
        {
            "Stops List":
            {
                "Stop-0":
                {
                    "Stops Alpha":
                        [
                            0.0, // offset
                            0.5, // midpoint
                            1.0  // alpha
                        ]
                },
                // More stops defined the same way...
            }
            "Stops Size": 2 // Number of stops
        },
        "Color Stops":
        {
            "Stops List":
            {
                "Stop-0":
                {
                    "Stops Color":
                    [
                        0.0, // offset
                        0.5, // midpoint
                        0.0, // red
                        0.0, // green
                        0.5, // blue
                        1.0  // alpha?
                    ]
                },
                // More stops defined the same way...
            }
            "Stops Size": 2 // Number of stops
        }
    },
    "Gradient Colors": "1.0" // Version?
}

Midpoint

You should use the "midpoint" values to add an additional color which is halfway between the other two.

For example given these stops:

    "Stop-0":
    {
        "Stops Color":
        [
            0.0, // offset
            0.5, // midpoint
            0.1, // red
            0.2, // green
            0.3, // blue
            1.0  // alpha?
        ]
    },
    "Stop-0":
    {
        "Stops Color":
        [
            0.6, // offset
            0.5, // midpoint
            0.3, // red
            0.4, // green
            0.5, // blue
            1.0  // alpha?
        ]
    },

The final gradient will look like this:

[
    // stop 0
    0.0, // offset_0
    0.1, // red_0
    0.2, // green_0
    0.3, // blue_0
    // midpoint stop
    0.3, // offset_0 * (1 - midpoint_0) + offset_1 * midpoint_0
    0.2, // (red_0 + red_1) / 2
    0.3, // (green_0 + green_1) / 2
    0.4, // (blue_0 + blue_1) / 2
    // stop 1
    0.6, // offset_1
    0.5, // midpoint_1
    0.3, // red_1
    0.4, // green_1
    0.5, // blue_1
]

Opacity

For some reason in AE gradients alpha is independent from the color, so you have separate stops for color and opacity.

You should treat the midpoint value for opacity stops in a similar way as to the color ones.

Once you have both the color and opacity values, the final lottie array is simply a concatenation of the two.

XMP Metadata

After the RIFX data, an AEP file also contains some XML in the XMP format.

This section contains the version of AfterEffects, when the file has been created and modified, and related info.

XML Project Format

Aftereffects allows you to save the project as XML.

This is basically as the RIFX but with a different container format and binary data encoded as hex.

Conversion notes for elements are provided below

AfterEffectsProject

Root element, same as RIFX.

ProjectXMPMetadata

In the RIFX file this is dumped at the end without a chunk.

string

Used instead of Utf8.

numS / ppSn

For some reason they have their value in a <string> but are not string in the RIFX.

tdsn / fnam / pdnm

These elements contain children but they are not LIST in RIFX, that's the only thing of note.

Child elements

If an element has children. it's the same as the equivalent LIST in RIFX.

bdata

Elements with the bdata attribute have their binary data hex encoded in said attribute.

You can parse their data the same way as you'd do in RIFX.

Resources