diff --git a/io_export_after_effects.py b/io_export_after_effects.py
index e5a26438d0cc39a88c6d8b468ba59369aac502fd..7aec1d1430de20a7006c0b892a3f52a0196ad3c0 100644
--- a/io_export_after_effects.py
+++ b/io_export_after_effects.py
@@ -22,8 +22,8 @@ bl_info = {
     "name": "Export: Adobe After Effects (.jsx)",
     "description": "Export cameras, selected objects & camera solution "
         "3D Markers to Adobe After Effects CS3 and above",
-    "author": "Bartek Skorupa, (Adi Samsonoff)",
-    "version": (0, 0, 66),
+    "author": "Bartek Skorupa",
+    "version": (0, 0, 67),
     "blender": (2, 80, 0),
     "location": "File > Export > Adobe After Effects (.jsx)",
     "warning": "",
@@ -34,13 +34,14 @@ bl_info = {
 
 
 import bpy
+import os
 import datetime
 from math import degrees, floor
-from mathutils import Matrix
+from mathutils import Matrix, Vector, Color
 
 
-# create list of static blender's data
 def get_comp_data(context):
+    """Create list of static blender's data"""
     scene = context.scene
     aspect_x = scene.render.pixel_aspect_x
     aspect_y = scene.render.pixel_aspect_y
@@ -64,8 +65,8 @@ def get_comp_data(context):
         }
 
 
-# create list of active camera for each frame in case active camera is set by markers
 def get_active_cam_for_each_frame(scene, start, end):
+    """Create list of active camera for each frame in case active camera is set by markers"""
     active_cam_frames = []
     sorted_markers = []
     markers = scene.timeline_markers
@@ -80,7 +81,8 @@ def get_active_cam_for_each_frame(scene, start, end):
                 for m, marker in enumerate(sorted_markers):
                     if marker[0] > frame:
                         if m != 0:
-                            active_cam_frames.append(sorted_markers[m - 1][1].camera)
+                            active_cam_frames.append(
+                                sorted_markers[m - 1][1].camera)
                         else:
                             active_cam_frames.append(marker[1].camera)
                         break
@@ -88,36 +90,41 @@ def get_active_cam_for_each_frame(scene, start, end):
                         active_cam_frames.append(marker[1].camera)
     if not active_cam_frames:
         if scene.camera:
-            # in this case active_cam_frames array will have legth of 1. This will indicate that there is only one active cam in all frames
+            # in this case active_cam_frames array will have length of 1. This
+            # will indicate that there is only one active cam in all frames
             active_cam_frames.append(scene.camera)
 
     return(active_cam_frames)
 
 
-# create managable list of selected objects
 def get_selected(context):
-    cameras = []  # list of selected cameras
-    solids = []  # list of all selected meshes that can be exported as AE's solids
-    lights = []  # list of all selected lamps that can be exported as AE's lights
-    nulls = []  # list of all selected objects exept cameras (will be used to create nulls in AE)
+    """Create manageable list of selected objects"""
+    cameras = []  # List of selected cameras
+    solids = []   # List of selected meshes exported as AE solids
+    images = []   # List of selected meshes exported as AE AV layers
+    lights = []   # List of selected lights exported as AE lights
+    nulls = []    # List of selected objects except cameras (will be used to create nulls in AE)
     obs = context.selected_objects
 
     for ob in obs:
         if ob.type == 'CAMERA':
-            cameras.append([ob, convert_name(ob.name)])
+            cameras.append(ob)
+
+        elif is_image_plane(ob):
+            images.append(ob)
 
         elif is_plane(ob):
-            # not ready yet. is_plane(object) returns False in all cases. This is temporary
-            solids.append([ob, convert_name(ob.name)])
+            solids.append(ob)
 
         elif ob.type == 'LIGHT':
-            lights.append([ob, ob.data.type + convert_name(ob.name)])  # Type of lamp added to name
+            lights.append(ob)
 
         else:
-            nulls.append([ob, convert_name(ob.name)])
+            nulls.append(ob)
 
     selection = {
         'cameras': cameras,
+        'images': images,
         'solids': solids,
         'lights': lights,
         'nulls': nulls,
@@ -126,14 +133,149 @@ def get_selected(context):
     return selection
 
 
-# check if object is plane and can be exported as AE's solid
-def is_plane(object):
-    # work in progress. Not ready yet
-    return False
+def get_first_material(obj):
+    for slot in obj.material_slots:
+        if slot.material is not None:
+            return slot.material
+
+
+def get_image_node(mat):
+    for node in mat.node_tree.nodes:
+        if node.type == "TEX_IMAGE":
+            return node.image
+
+
+def get_plane_color(obj):
+    """Get the object's emission and base color, or 0.5 gray if no color is found."""
+    if obj.active_material is None:
+        color = (0.5,) * 3
+    elif obj.active_material:
+        from bpy_extras import node_shader_utils
+        wrapper = node_shader_utils.PrincipledBSDFWrapper(obj.active_material)
+        color = Color(wrapper.base_color[:3]) + wrapper.emission_color
+
+    return '[%f,%f,%f]' % (color[0], color[1], color[2])
+
+
+def is_plane(obj):
+    """Check if object is a plane
+
+    Makes a few assumptions:
+    - The mesh has exactly one quad face
+    - The mesh is a rectangle
+
+    For now this doesn't account for shear, which could happen e.g. if the
+    vertices are rotated, and the object is scaled non-uniformly...
+    """
+    if obj.type != 'MESH':
+        return False
+
+    if len(obj.data.polygons) != 1:
+        return False
+
+    if len(obj.data.polygons[0].vertices) != 4:
+        return False
+
+    v1, v2, v3, v4 = (obj.data.vertices[v].co for v in obj.data.polygons[0].vertices)
+
+    # Check that poly is a parallelogram
+    if -v1 + v2 + v4 != v3:
+        return False
+
+    # Check that poly has at least one right angle
+    if (v2-v1).dot(v4-v1) != 0.0:
+        return False
+
+    # If my calculations are correct, that should make it a rectangle
+    return True
+
+
+def is_image_plane(obj):
+    """Check if object is a plane with an image
+
+    Makes a few assumptions:
+    - The mesh is a plane
+    - The mesh has exactly one material
+    - There is only one image in this material node tree
+    """
+    if not is_plane(obj):
+        return False
+
+    if not len(obj.material_slots):
+        return False
+
+    mat = get_first_material(obj)
+    if mat is None:
+        return False
+
+    img = get_image_node(mat)
+    if img is None:
+        return False
+
+    if len(obj.data.vertices) == 4:
+        return True
+
+
+def get_image_filepath(obj):
+    mat = get_first_material(obj)
+    img = get_image_node(mat)
+    filepath = img.filepath
+    filepath = bpy.path.abspath(filepath)
+    filepath = os.path.abspath(filepath)
+    filepath = filepath.replace('\\', '\\\\')
+    return filepath
+
+
+def get_image_size(obj):
+    mat = get_first_material(obj)
+    img = get_image_node(mat)
+    return img.size
+
+
+def get_plane_matrix(obj):
+    """Get object's polygon local matrix from vertices."""
+    v1, v2, v3, v4 = (obj.data.vertices[v].co for v in obj.data.polygons[0].vertices)
+
+    p0 = obj.matrix_world @ v1
+    px = obj.matrix_world @ v2 - p0
+    py = obj.matrix_world @ v4 - p0
+
+    rot_mat = Matrix((px, py, px.cross(py))).transposed().to_4x4()
+    trans_mat = Matrix.Translation(p0 + (px + py) / 2.0)
+    mat = trans_mat @ rot_mat
+
+    return mat
+
+
+def get_image_plane_matrix(obj):
+    """Get object's polygon local matrix from uvs.
+
+    This will only work if uvs occupy all space, to get bounds
+    """
+    for p_i, p in enumerate(obj.data.uv_layers.active.data):
+        if p.uv == Vector((0, 0)):
+            p0 = p_i
+        elif p.uv == Vector((1, 0)):
+            px = p_i
+        elif p.uv == Vector((0, 1)):
+            py = p_i
+
+    verts = obj.data.vertices
+    loops = obj.data.loops
+
+    p0 = obj.matrix_world @ verts[loops[p0].vertex_index].co
+    px = obj.matrix_world @ verts[loops[px].vertex_index].co - p0
+    py = obj.matrix_world @ verts[loops[py].vertex_index].co - p0
+
+    rot_mat = Matrix((px, py, px.cross(py))).transposed().to_4x4()
+    trans_mat = Matrix.Translation(p0 + (px + py) / 2.0)
+    mat = trans_mat @ rot_mat
+
+    return mat
 
 
-# convert names of objects to avoid errors in AE.
 def convert_name(name):
+    """Convert names of objects to avoid errors in AE"""
     name = "_" + name
     '''
     # Digits are not allowed at beginning of AE vars names.
@@ -148,38 +290,51 @@ def convert_name(name):
     return name
 
 
-# get object's blender's location rotation and scale and return AE's Position, Rotation/Orientation and scale
-# this function will be called for every object for every frame
-def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=False):
+def convert_transform_matrix(matrix, width, height, aspect,
+                             x_rot_correction=False, ae_size=100.0):
+    """Convert from Blender's Location, Rotation and Scale
+    to AE's Position, Rotation/Orientation and Scale
 
-    # get blender transform data for ob
-    b_loc = matrix.to_translation()
+    This function will be called for every object for every frame
+    """
+
+    scale_mat = Matrix.Scale(width, 4)
+
+    # Get blender transform data for ob
+    b_loc = (scale_mat @ matrix).to_translation()
     b_rot = matrix.to_euler('ZYX')  # ZYX euler matches AE's orientation and allows to use x_rot_correction
     b_scale = matrix.to_scale()
 
-    # convert to AE Position Rotation and Scale
-    # Axes in AE are different. AE's X is blender's X, AE's Y is negative Blender's Z, AE's Z is Blender's Y
-    x = (b_loc.x * 100.0) / aspect + width / 2.0  # calculate AE's X position
-    y = (-b_loc.z * 100.0) + (height / 2.0)  # calculate AE's Y position
-    z = b_loc.y * 100.0  # calculate AE's Z position
+    # Convert to AE Position Rotation and Scale. Axes in AE are different:
+    # AE's X is Blender's X,
+    # AE's Y is Blender's -Z,
+    # AE's Z is Blender's Y
+    x = (b_loc.x * ae_size / 100.0) / aspect + width / 2.0
+    y = (-b_loc.z * ae_size / 100.0) + (height / 2.0)
+    z = (b_loc.y * ae_size / 100.0)
+
     # Convert rotations to match AE's orientation.
-    rx = degrees(b_rot.x)  # if not x_rot_correction - AE's X orientation = blender's X rotation if 'ZYX' euler.
-    ry = -degrees(b_rot.y)  # AE's Y orientation is negative blender's Y rotation if 'ZYX' euler
-    rz = -degrees(b_rot.z)  # AE's Z orientation is negative blender's Z rotation if 'ZYX' euler
+    # If not x_rot_correction
+    rx =  degrees(b_rot.x)  # AE's X orientation =  blender's X rotation if 'ZYX' euler.
+    ry = -degrees(b_rot.y)  # AE's Y orientation = -blender's Y rotation if 'ZYX' euler
+    rz = -degrees(b_rot.z)  # AE's Z orientation = -blender's Z rotation if 'ZYX' euler
     if x_rot_correction:
-        rx -= 90.0  # In blender - ob of zero rotation lay on floor. In AE layer of zero orientation "stands"
-    # Convert scale to AE scale
-    sx = b_scale.x * 100.0  # scale of 1.0 is 100% in AE
-    sy = b_scale.z * 100.0  # scale of 1.0 is 100% in AE
-    sz = b_scale.y * 100.0  # scale of 1.0 is 100% in AE
+        # In Blender, ob of zero rotation lays on floor.
+        # In AE, layer of zero orientation "stands"
+        rx -= 90.0
+    # Convert scale to AE scale. ae_size is a global multiplier.
+    sx = b_scale.x * ae_size
+    sy = b_scale.y * ae_size
+    sz = b_scale.z * ae_size
 
     return x, y, z, rx, ry, rz, sx, sy, sz
 
-# get camera's lens and convert to AE's "zoom" value in pixels
+# Get camera's lens and convert to AE's "zoom" value in pixels
 # this function will be called for every camera for every frame
 #
 #
-# AE's lens is defined by "zoom" in pixels. Zoom determines focal angle or focal length.
+# AE's lens is defined by "zoom" in pixels.
+# Zoom determines focal angle or focal length.
 #
 # ZOOM VALUE CALCULATIONS:
 #
@@ -193,10 +348,16 @@ def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=Fal
 #     - PAR (pixel aspect ratio)
 #
 # Calculations are made using sensor's size and scene/comp dimension (width or height).
-# If camera.sensor_fit is set to 'AUTO' or 'HORIZONTAL' - sensor = camera.data.sensor_width, dimension = width.
-# If camera.sensor_fit is set to 'VERTICAL' - sensor = camera.data.sensor_height, dimension = height
+# If camera.sensor_fit is set to 'HORIZONTAL':
+#     sensor = camera.data.sensor_width, dimension = width.
+# If camera.sensor_fit is set to 'AUTO'
+# and the vertical size is greater than the horizontal size:
+#     sensor = camera.data.sensor_width, dimension = width.
 #
-# zoom can be calculated using simple proportions.
+# If camera.sensor_fit is set to 'VERTICAL':
+#    sensor = camera.data.sensor_height, dimension = height
+#
+# Zoom can be calculated using simple proportions.
 #
 #                             |
 #                           / |
@@ -214,15 +375,18 @@ def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=Fal
 #          |     |            |
 #           lens |    zoom
 #
-#    zoom / dimension = lens / sensor   =>
-#    zoom = lens * dimension / sensor
+#     zoom / dimension = lens / sensor   =>
+#     zoom = lens * dimension / sensor
 #
-#    above is true if square pixels are used. If not - aspect compensation is needed, so final formula is:
-#    zoom = lens * dimension / sensor * aspect
+# Above is true if square pixels are used. If not,
+# aspect compensation is needed, so final formula is:
+#     zoom = lens * dimension / sensor * aspect
 
 
 def convert_lens(camera, width, height, aspect):
-    if camera.data.sensor_fit == 'VERTICAL':
+    if (camera.data.sensor_fit == 'VERTICAL'
+            or camera.data.sensor_fit == 'AUTO'
+            and (width / height) * aspect < 0):
         sensor = camera.data.sensor_height
         dimension = height
     else:
@@ -234,37 +398,44 @@ def convert_lens(camera, width, height, aspect):
     return zoom
 
 # convert object bundle's matrix. Not ready yet. Temporarily not active
-#def get_ob_bundle_matrix_world(cam_matrix_world, bundle_matrix):
+# def get_ob_bundle_matrix_world(cam_matrix_world, bundle_matrix):
 #    matrix = cam_matrix_basis
 #    return matrix
 
 
-# jsx script for AE creation
-def write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles):
+def write_jsx_file(file, data, selection, include_animation,
+                   include_active_cam, include_selected_cams,
+                   include_selected_objects, include_cam_bundles,
+                   include_image_planes, ae_size):
+    """jsx script for AE creation"""
 
     print("\n---------------------------\n- Export to After Effects -\n---------------------------")
-    # store the current frame to restore it at the end of export
+    # Store the current frame to restore it at the end of export
     curframe = data['curframe']
-    # create array which will contain all keyframes values
+    # Create array which will contain all keyframes values
     js_data = {
         'times': '',
         'cameras': {},
-        'solids': {},  # not ready yet
+        'images': {},
+        'solids': {},
         'lights': {},
         'nulls': {},
         'bundles_cam': {},
         'bundles_ob': {},  # not ready yet
         }
 
-    # create structure for active camera/cameras
+    # Create structure for active camera/cameras
     active_cam_name = ''
-    if include_active_cam and data['active_cam_frames'] != []:
-        # check if more that one active cam exist (true if active cams set by markers)
+    if include_active_cam and data['active_cam_frames']:
+        # Check if more than one active cam exists
+        # (True if active cams set by markers)
         if len(data['active_cam_frames']) == 1:
-            name_ae = convert_name(data['active_cam_frames'][0].name)  # take name of the only active camera in scene
+            # Take name of the only active camera in scene
+            name_ae = convert_name(data['active_cam_frames'][0].name)
         else:
             name_ae = 'Active_Camera'
-        active_cam_name = name_ae  # store name to be used when creating keyframes for active cam.
+        # Store name to be used when creating keyframes for active cam
+        active_cam_name = name_ae
         js_data['cameras'][name_ae] = {
             'position': '',
             'position_static': '',
@@ -277,11 +448,12 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
             'zoom_anim': False,
             }
 
-    # create camera structure for selected cameras
+    # Create camera structure for selected cameras
     if include_selected_cams:
-        for i, cam in enumerate(selection['cameras']):  # more than one camera can be selected
-            if cam[1] != active_cam_name:
-                name_ae = selection['cameras'][i][1]
+        for obj in selection['cameras']:
+            # More than one camera can be selected
+            if convert_name(obj.name) != active_cam_name:
+                name_ae = convert_name(obj.name)
                 js_data['cameras'][name_ae] = {
                     'position': '',
                     'position_static': '',
@@ -293,35 +465,56 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                     'zoom_static': '',
                     'zoom_anim': False,
                     }
-    '''
-    # create structure for solids. Not ready yet. Temporarily not active
-    for i, obj in enumerate(selection['solids']):
-        name_ae = selection['solids'][i][1]
+
+    # Create structure for solids
+    for obj in selection['solids']:
+        name_ae = convert_name(obj.name)
         js_data['solids'][name_ae] = {
             'position': '',
+            'position_static': '',
+            'position_anim': False,
             'orientation': '',
-            'rotationX': '',
+            'orientation_static': '',
+            'orientation_anim': False,
             'scale': '',
+            'scale_static': '',
+            'scale_anim': False,
             }
-    '''
-    # create structure for lights
-    for i, obj in enumerate(selection['lights']):
+
+    # Create structure for images
+    for obj in selection['images']:
+        name_ae = convert_name(obj.name)
+        js_data['images'][name_ae] = {
+            'position': '',
+            'position_static': '',
+            'position_anim': False,
+            'orientation': '',
+            'orientation_static': '',
+            'orientation_anim': False,
+            'scale': '',
+            'scale_static': '',
+            'scale_anim': False,
+            'filepath': '',
+        }
+
+    # Create structure for lights
+    for obj in selection['lights']:
         if include_selected_objects:
-            name_ae = selection['lights'][i][1]
+            name_ae = obj.data.type + convert_name(obj.name)
             js_data['lights'][name_ae] = {
-                'type': selection['lights'][i][0].data.type,
-                'energy': '',
-                'energy_static': '',
-                'energy_anim': False,
-                'cone_angle': '',
-                'cone_angle_static': '',
-                'cone_angle_anim': False,
-                'cone_feather': '',
-                'cone_feather_static': '',
-                'cone_feather_anim': False,
-                'color': '',
-                'color_static': '',
-                'color_anim': False,
+                'type': obj.data.type,
+                'intensity': '',
+                'intensity_static': '',
+                'intensity_anim': False,
+                'Cone Angle': '',
+                'Cone Angle_static': '',
+                'Cone Angle_anim': False,
+                'Cone Feather': '',
+                'Cone Feather_static': '',
+                'Cone Feather_anim': False,
+                'Color': '',
+                'Color_static': '',
+                'Color_anim': False,
                 'position': '',
                 'position_static': '',
                 'position_anim': False,
@@ -330,10 +523,11 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                 'orientation_anim': False,
                 }
 
-    # create structure for nulls
-    for i, obj in enumerate(selection['nulls']):  # nulls representing blender's obs except cameras, lights and solids
+    # Create structure for nulls
+    # nulls representing blender's obs except cameras, lights and solids
+    for obj in selection['nulls']:
         if include_selected_objects:
-            name_ae = selection['nulls'][i][1]
+            name_ae = convert_name(obj.name)
             js_data['nulls'][name_ae] = {
                 'position': '',
                 'position_static': '',
@@ -346,23 +540,24 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                 'scale_anim': False,
                 }
 
-    # create structure for cam bundles including positions (cam bundles don't move)
+    # Create structure for cam bundles including positions
+    # (cam bundles don't move)
     if include_cam_bundles:
-        # go through each selected camera and active cameras
+        # Go through each selected camera and active cameras
         selected_cams = []
         active_cams = []
         if include_active_cam:
             active_cams = data['active_cam_frames']
         if include_selected_cams:
             for cam in selection['cameras']:
-                selected_cams.append(cam[0])
-        # list of cameras that will be checked for 'CAMERA SOLVER'
+                selected_cams.append(cam)
+        # List of cameras that will be checked for 'CAMERA SOLVER'
         cams = list(set.union(set(selected_cams), set(active_cams)))
 
         for cam in cams:
-            # go through each constraints of this camera
+            # Go through each constraints of this camera
             for constraint in cam.constraints:
-                # does the camera have a Camera Solver constraint
+                # Does the camera have a Camera Solver constraint
                 if constraint.type == 'CAMERA_SOLVER':
                     # Which movie clip does it use
                     if constraint.use_active_clip:
@@ -370,22 +565,28 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                     else:
                         clip = constraint.clip
 
-                    # go through each tracking point
+                    # Go through each tracking point
                     for track in clip.tracking.tracks:
-                        # Does this tracking point have a bundle (has its 3D position been solved)
+                        # Does this tracking point have a bundle
+                        # (has its 3D position been solved)
                         if track.has_bundle:
-                            # get the name of the tracker
-                            name_ae = convert_name(str(cam.name) + '__' + str(track.name))
+                            # Get the name of the tracker
+                            name_ae = convert_name(str(cam.name) + '__' +
+                                                   str(track.name))
                             js_data['bundles_cam'][name_ae] = {
                                 'position': '',
                                 }
-                            # bundles are in camera space. Transpose to world space
-                            matrix = Matrix.Translation(cam.matrix_basis.copy() @ track.bundle)
-                            # convert the position into AE space
-                            ae_transform = convert_transform_matrix(matrix, data['width'], data['height'], data['aspect'], x_rot_correction=False)
-                            js_data['bundles_cam'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
-
-    # get all keyframes for each object and store in dico
+                            # Bundles are in camera space.
+                            # Transpose to world space
+                            matrix = Matrix.Translation(cam.matrix_basis.copy()
+                                                        @ track.bundle)
+                            # Convert the position into AE space
+                            ae_transform = (convert_transform_matrix(
+                                matrix, data['width'], data['height'],
+                                data['aspect'], False, ae_size))
+                            js_data['bundles_cam'][name_ae]['position'] += ('[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]))
+
+    # Get all keyframes for each object and store in dico
     if include_animation:
         end = data['end'] + 1
     else:
@@ -394,154 +595,259 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
         print("working on frame: " + str(frame))
         data['scn'].frame_set(frame)
 
-        # get time for this loop
-        js_data['times'] += '%f ,' % ((frame - data['start']) / data['fps'])
+        # Get time for this loop
+        js_data['times'] += '%f,' % ((frame - data['start']) / data['fps'])
 
-        # keyframes for active camera/cameras
+        # Keyframes for active camera/cameras
         if include_active_cam and data['active_cam_frames'] != []:
             if len(data['active_cam_frames']) == 1:
                 cur_cam_index = 0
             else:
                 cur_cam_index = frame - data['start']
             active_cam = data['active_cam_frames'][cur_cam_index]
-            # get cam name
+            # Get cam name
             name_ae = active_cam_name
-            # convert cam transform properties to AE space
-            ae_transform = convert_transform_matrix(active_cam.matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
-            # convert Blender's lens to AE's zoom in pixels
-            zoom = convert_lens(active_cam, data['width'], data['height'], data['aspect'])
-            # store all values in dico
-            position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
-            orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4], ae_transform[5])
+            # Convert cam transform properties to AE space
+            ae_transform = (convert_transform_matrix(
+                active_cam.matrix_world.copy(), data['width'], data['height'],
+                data['aspect'], True, ae_size))
+            # Convert Blender's lens to AE's zoom in pixels
+            zoom = convert_lens(active_cam, data['width'], data['height'],
+                                data['aspect'])
+            # Store all values in dico
+            position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1],
+                                        ae_transform[2])
+            orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4],
+                                           ae_transform[5])
             zoom = '%f,' % (zoom)
-            js_data['cameras'][name_ae]['position'] += position
-            js_data['cameras'][name_ae]['orientation'] += orientation
-            js_data['cameras'][name_ae]['zoom'] += zoom
+            js_camera = js_data['cameras'][name_ae]
+            js_camera['position'] += position
+            js_camera['orientation'] += orientation
+            js_camera['zoom'] += zoom
             # Check if properties change values compared to previous frame
-            # If property don't change through out the whole animation - keyframes won't be added
+            # If property don't change through out the whole animation,
+            # keyframes won't be added
             if frame != data['start']:
-                if position != js_data['cameras'][name_ae]['position_static']:
-                    js_data['cameras'][name_ae]['position_anim'] = True
-                if orientation != js_data['cameras'][name_ae]['orientation_static']:
-                    js_data['cameras'][name_ae]['orientation_anim'] = True
-                if zoom != js_data['cameras'][name_ae]['zoom_static']:
-                    js_data['cameras'][name_ae]['zoom_anim'] = True
-            js_data['cameras'][name_ae]['position_static'] = position
-            js_data['cameras'][name_ae]['orientation_static'] = orientation
-            js_data['cameras'][name_ae]['zoom_static'] = zoom
-
-        # keyframes for selected cameras
+                if position != js_camera['position_static']:
+                    js_camera['position_anim'] = True
+                if orientation != js_camera['orientation_static']:
+                    js_camera['orientation_anim'] = True
+                if zoom != js_camera['zoom_static']:
+                    js_camera['zoom_anim'] = True
+            js_camera['position_static'] = position
+            js_camera['orientation_static'] = orientation
+            js_camera['zoom_static'] = zoom
+
+        # Keyframes for selected cameras
         if include_selected_cams:
-            for i, cam in enumerate(selection['cameras']):
-                if cam[1] != active_cam_name:
-                    # get cam name
-                    name_ae = selection['cameras'][i][1]
-                    # convert cam transform properties to AE space
-                    ae_transform = convert_transform_matrix(cam[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
-                    # convert Blender's lens to AE's zoom in pixels
-                    zoom = convert_lens(cam[0], data['width'], data['height'], data['aspect'])
-                    # store all values in dico
-                    position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
-                    orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4], ae_transform[5])
+            for obj in selection['cameras']:
+                if convert_name(obj.name) != active_cam_name:
+                    # Get cam name
+                    name_ae = convert_name(obj.name)
+                    # Convert cam transform properties to AE space
+                    ae_transform = convert_transform_matrix(
+                        obj.matrix_world.copy(), data['width'],
+                        data['height'], data['aspect'], True, ae_size)
+                    # Convert Blender's lens to AE's zoom in pixels
+                    zoom = convert_lens(obj, data['width'], data['height'],
+                                        data['aspect'])
+                    # Store all values in dico
+                    position = '[%f,%f,%f],' % (ae_transform[0],
+                                                ae_transform[1],
+                                                ae_transform[2])
+                    orientation = '[%f,%f,%f],' % (ae_transform[3],
+                                                   ae_transform[4],
+                                                   ae_transform[5])
                     zoom = '%f,' % (zoom)
-                    js_data['cameras'][name_ae]['position'] += position
-                    js_data['cameras'][name_ae]['orientation'] += orientation
-                    js_data['cameras'][name_ae]['zoom'] += zoom
+                    js_camera = js_data['cameras'][name_ae]
+                    js_camera['position'] += position
+                    js_camera['orientation'] += orientation
+                    js_camera['zoom'] += zoom
                     # Check if properties change values compared to previous frame
-                    # If property don't change through out the whole animation - keyframes won't be added
+                    # If property don't change through out the whole animation,
+                    # keyframes won't be added
                     if frame != data['start']:
-                        if position != js_data['cameras'][name_ae]['position_static']:
-                            js_data['cameras'][name_ae]['position_anim'] = True
-                        if orientation != js_data['cameras'][name_ae]['orientation_static']:
-                            js_data['cameras'][name_ae]['orientation_anim'] = True
-                        if zoom != js_data['cameras'][name_ae]['zoom_static']:
-                            js_data['cameras'][name_ae]['zoom_anim'] = True
-                    js_data['cameras'][name_ae]['position_static'] = position
-                    js_data['cameras'][name_ae]['orientation_static'] = orientation
-                    js_data['cameras'][name_ae]['zoom_static'] = zoom
-
-        '''
-        # keyframes for all solids. Not ready yet. Temporarily not active
-        for i, ob in enumerate(selection['solids']):
-            #get object name
-            name_ae = selection['solids'][i][1]
-            #convert ob position to AE space
-        '''
-
-        # keyframes for all lights.
+                        if position != js_camera['position_static']:
+                            js_camera['position_anim'] = True
+                        if orientation != js_camera['orientation_static']:
+                            js_camera['orientation_anim'] = True
+                        if zoom != js_camera['zoom_static']:
+                            js_camera['zoom_anim'] = True
+                    js_camera['position_static'] = position
+                    js_camera['orientation_static'] = orientation
+                    js_camera['zoom_static'] = zoom
+
+        # Keyframes for all solids.
+        if include_selected_objects:
+            for obj in selection['solids']:
+                # Get object name
+                name_ae = convert_name(obj.name)
+                # Convert obj transform properties to AE space
+                plane_matrix = get_plane_matrix(obj)
+                ae_transform = convert_transform_matrix(
+                    plane_matrix, data['width'], data['height'],
+                    data['aspect'], True, ae_size)
+                # Store all values in dico
+                position = '[%f,%f,%f],' % (ae_transform[0],
+                                            ae_transform[1],
+                                            ae_transform[2])
+                orientation = '[%f,%f,%f],' % (ae_transform[3],
+                                               ae_transform[4],
+                                               ae_transform[5])
+                # plane_width, plane_height, _ = plane_matrix.to_scale()
+                scale = '[%f,%f,%f],' % (ae_transform[6],
+                                         ae_transform[7] * data['width'] / data['height'],
+                                         ae_transform[8])
+                js_solid = js_data['solids'][name_ae]
+                js_solid['color'] = get_plane_color(obj)
+                js_solid['width'] = data['width']
+                js_solid['height'] = data['height']
+                js_solid['position'] += position
+                js_solid['orientation'] += orientation
+                js_solid['scale'] += scale
+                # Check if properties change values compared to previous frame
+                # If property don't change through out the whole animation,
+                # keyframes won't be added
+                if frame != data['start']:
+                    if position != js_solid['position_static']:
+                        js_solid['position_anim'] = True
+                    if orientation != js_solid['orientation_static']:
+                        js_solid['orientation_anim'] = True
+                    if scale != js_solid['scale_static']:
+                        js_solid['scale_anim'] = True
+                js_solid['position_static'] = position
+                js_solid['orientation_static'] = orientation
+                js_solid['scale_static'] = scale
+
+        # Keyframes for all lights.
         if include_selected_objects:
-            for i, ob in enumerate(selection['lights']):
-                #get object name
-                name_ae = selection['lights'][i][1]
-                type = selection['lights'][i][0].data.type
-                # convert ob transform properties to AE space
-                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
-                color = ob[0].data.color
-                # store all values in dico
-                position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
-                orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4], ae_transform[5])
-                energy = '[%f],' % (ob[0].data.energy * 100.0)
+            for obj in selection['lights']:
+                # Get object name
+                name_ae = obj.data.type + convert_name(obj.name)
+                type = obj.data.type
+                # Convert ob transform properties to AE space
+                ae_transform = convert_transform_matrix(
+                    obj.matrix_world.copy(), data['width'], data['height'],
+                    data['aspect'], True, ae_size)
+                color = obj.data.color
+                # Store all values in dico
+                position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1],
+                                            ae_transform[2])
+                orientation = '[%f,%f,%f],' % (ae_transform[3],
+                                               ae_transform[4],
+                                               ae_transform[5])
+                energy = '[%f],' % (obj.data.energy * 100.0)
                 color = '[%f,%f,%f],' % (color[0], color[1], color[2])
-                js_data['lights'][name_ae]['position'] += position
-                js_data['lights'][name_ae]['orientation'] += orientation
-                js_data['lights'][name_ae]['energy'] += energy
-                js_data['lights'][name_ae]['color'] += color
+                js_light = js_data['lights'][name_ae]
+                js_light['position'] += position
+                js_light['orientation'] += orientation
+                js_light['intensity'] += energy
+                js_light['Color'] += color
                 # Check if properties change values compared to previous frame
-                # If property don't change through out the whole animation - keyframes won't be added
+                # If property don't change through out the whole animation,
+                # keyframes won't be added
                 if frame != data['start']:
-                    if position != js_data['lights'][name_ae]['position_static']:
-                        js_data['lights'][name_ae]['position_anim'] = True
-                    if orientation != js_data['lights'][name_ae]['orientation_static']:
-                        js_data['lights'][name_ae]['orientation_anim'] = True
-                    if energy != js_data['lights'][name_ae]['energy_static']:
-                        js_data['lights'][name_ae]['energy_anim'] = True
-                    if color != js_data['lights'][name_ae]['color_static']:
-                        js_data['lights'][name_ae]['color_anim'] = True
-                js_data['lights'][name_ae]['position_static'] = position
-                js_data['lights'][name_ae]['orientation_static'] = orientation
-                js_data['lights'][name_ae]['energy_static'] = energy
-                js_data['lights'][name_ae]['color_static'] = color
+                    if position != js_light['position_static']:
+                        js_light['position_anim'] = True
+                    if orientation != js_light['orientation_static']:
+                        js_light['orientation_anim'] = True
+                    if energy != js_light['intensity_static']:
+                        js_light['intensity_anim'] = True
+                    if color != js_light['Color_static']:
+                        js_light['Color_anim'] = True
+                js_light['position_static'] = position
+                js_light['orientation_static'] = orientation
+                js_light['intensity_static'] = energy
+                js_light['Color_static'] = color
                 if type == 'SPOT':
-                    cone_angle = '[%f],' % (degrees(ob[0].data.spot_size))
-                    cone_feather = '[%f],' % (ob[0].data.spot_blend * 100.0)
-                    js_data['lights'][name_ae]['cone_angle'] += cone_angle
-                    js_data['lights'][name_ae]['cone_feather'] += cone_feather
+                    cone_angle = '[%f],' % (degrees(obj.data.spot_size))
+                    cone_feather = '[%f],' % (obj.data.spot_blend * 100.0)
+                    js_light['Cone Angle'] += cone_angle
+                    js_light['Cone Feather'] += cone_feather
                     # Check if properties change values compared to previous frame
-                    # If property don't change through out the whole animation - keyframes won't be added
+                    # If property don't change through out the whole animation,
+                    # keyframes won't be added
                     if frame != data['start']:
-                        if cone_angle != js_data['lights'][name_ae]['cone_angle_static']:
-                            js_data['lights'][name_ae]['cone_angle_anim'] = True
-                        if orientation != js_data['lights'][name_ae]['cone_feather_static']:
-                            js_data['lights'][name_ae]['cone_feather_anim'] = True
-                    js_data['lights'][name_ae]['cone_angle_static'] = cone_angle
-                    js_data['lights'][name_ae]['cone_feather_static'] = cone_feather
-
-        # keyframes for all nulls
+                        if cone_angle != js_light['Cone Angle_static']:
+                            js_light['Cone Angle_anim'] = True
+                        if cone_feather != js_light['Cone Feather_static']:
+                            js_light['Cone Feather_anim'] = True
+                    js_light['Cone Angle_static'] = cone_angle
+                    js_light['Cone Feather_static'] = cone_feather
+
+        # Keyframes for all nulls
         if include_selected_objects:
-            for i, ob in enumerate(selection['nulls']):
-                # get object name
-                name_ae = selection['nulls'][i][1]
-                # convert ob transform properties to AE space
-                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
-                # store all values in dico
-                position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
-                orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4], ae_transform[5])
-                scale = '[%f,%f,%f],' % (ae_transform[6], ae_transform[7], ae_transform[8])
-                js_data['nulls'][name_ae]['position'] += position
-                js_data['nulls'][name_ae]['orientation'] += orientation
-                js_data['nulls'][name_ae]['scale'] += scale
+            for obj in selection['nulls']:
+                # Get object name
+                name_ae = convert_name(obj.name)
+                # Convert obj transform properties to AE space
+                ae_transform = convert_transform_matrix(obj.matrix_world.copy(), data['width'], data['height'], data['aspect'], True, ae_size)
+                # Store all values in dico
+                position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1],
+                                            ae_transform[2])
+                orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4],
+                                               ae_transform[5])
+                scale = '[%f,%f,%f],' % (ae_transform[6], ae_transform[7],
+                                         ae_transform[8])
+                js_null = js_data['nulls'][name_ae]
+                js_null['position'] += position
+                js_null['orientation'] += orientation
+                js_null['scale'] += scale
+                # Check if properties change values compared to previous frame
+                # If property don't change through out the whole animation,
+                # keyframes won't be added
+                if frame != data['start']:
+                    if position != js_null['position_static']:
+                        js_null['position_anim'] = True
+                    if orientation != js_null['orientation_static']:
+                        js_null['orientation_anim'] = True
+                    if scale != js_null['scale_static']:
+                        js_null['scale_anim'] = True
+                js_null['position_static'] = position
+                js_null['orientation_static'] = orientation
+                js_null['scale_static'] = scale
+
+        # Keyframes for all images
+        if include_image_planes:
+            for obj in selection['images']:
+                # Get object name
+                name_ae = convert_name(obj.name)
+                # Convert obj transform properties to AE space
+                plane_matrix = get_image_plane_matrix(obj)
+                ae_transform = convert_transform_matrix(
+                    plane_matrix, data['width'], data['height'],
+                    data['aspect'], True, ae_size)
+                # Store all values in dico
+                position = '[%f,%f,%f],' % (ae_transform[0],
+                                            ae_transform[1],
+                                            ae_transform[2])
+                orientation = '[%f,%f,%f],' % (ae_transform[3],
+                                               ae_transform[4],
+                                               ae_transform[5])
+                image_width, image_height = get_image_size(obj)
+                ratio_to_comp = image_width / data['width']
+                scale = '[%f,%f,%f],' % (ae_transform[6] / ratio_to_comp,
+                                         ae_transform[7] / ratio_to_comp
+                                         * image_width / image_height,
+                                         ae_transform[8])
+                js_image = js_data['images'][name_ae]
+                js_image['position'] += position
+                js_image['orientation'] += orientation
+                js_image['scale'] += scale
                 # Check if properties change values compared to previous frame
-                # If property don't change through out the whole animation - keyframes won't be added
+                # If property don't change through out the whole animation,
+                # keyframes won't be added
                 if frame != data['start']:
-                    if position != js_data['nulls'][name_ae]['position_static']:
-                        js_data['nulls'][name_ae]['position_anim'] = True
-                    if orientation != js_data['nulls'][name_ae]['orientation_static']:
-                        js_data['nulls'][name_ae]['orientation_anim'] = True
-                    if scale != js_data['nulls'][name_ae]['scale_static']:
-                        js_data['nulls'][name_ae]['scale_anim'] = True
-                js_data['nulls'][name_ae]['position_static'] = position
-                js_data['nulls'][name_ae]['orientation_static'] = orientation
-                js_data['nulls'][name_ae]['scale_static'] = scale
+                    if position != js_image['position_static']:
+                        js_image['position_anim'] = True
+                    if orientation != js_image['orientation_static']:
+                        js_image['orientation_anim'] = True
+                    if scale != js_image['scale_static']:
+                        js_image['scale_anim'] = True
+                js_image['position_static'] = position
+                js_image['orientation_static'] = orientation
+                js_image['scale_static'] = scale
+                js_image['filepath'] = get_image_filepath(obj)
 
         # keyframes for all object bundles. Not ready yet.
         #
@@ -551,7 +857,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
     # ---- write JSX file
     jsx_file = open(file, 'w')
 
-    # make the jsx executable in After Effects (enable double click on jsx)
+    # Make the jsx executable in After Effects (enable double click on jsx)
     jsx_file.write('#target AfterEffects\n\n')
     # Script's header
     jsx_file.write('/**************************************\n')
@@ -563,138 +869,185 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
     jsx_file.write('Exported with io_export_after_effects.py\n')
     jsx_file.write('**************************************/\n\n\n\n')
 
-    # wrap in function
+    # Wrap in function
     jsx_file.write("function compFromBlender(){\n")
-    # create new comp
-    jsx_file.write('\nvar compName = prompt("Blender Comp\'s Name \\nEnter Name of newly created Composition","BlendComp","Composition\'s Name");\n')
-    jsx_file.write('if (compName){')  # Continue only if comp name is given. If not - terminate
-    jsx_file.write('\nvar newComp = app.project.items.addComp(compName, %i, %i, %f, %f, %f);' %
-                   (data['width'], data['height'], data['aspect'], data['duration'], data['fps']))
-    jsx_file.write('\nnewComp.displayStartTime = %f;\n\n\n' % ((data['start'] + 1.0) / data['fps']))
-
-    # create camera bundles (nulls)
-    jsx_file.write('// **************  CAMERA 3D MARKERS  **************\n\n\n')
-    for i, obj in enumerate(js_data['bundles_cam']):
-        name_ae = obj
+    # Create new comp
+    if bpy.data.filepath:
+        comp_name = convert_name(
+            os.path.splitext(os.path.basename(bpy.data.filepath))[0])
+    else:
+        comp_name = "BlendComp"
+    jsx_file.write('\nvar compName = prompt("Blender Comp\'s Name \\nEnter Name of newly created Composition","%s","Composition\'s Name");\n' % comp_name)
+    jsx_file.write('if (compName){')
+    # Continue only if comp name is given. If not - terminate
+    jsx_file.write(
+        '\nvar newComp = app.project.items.addComp(compName, %i, %i, %f, %f, %f);'
+        % (data['width'], data['height'], data['aspect'],
+           data['duration'], data['fps']))
+    jsx_file.write('\nnewComp.displayStartTime = %f;\n\n\n'
+                   % ((data['start'] + 1.0) / data['fps']))
+
+    # Create camera bundles (nulls)
+    jsx_file.write('// **************  CAMERA 3D MARKERS  **************\n\n')
+    for name_ae, obj in js_data['bundles_cam'].items():
         jsx_file.write('var %s = newComp.layers.addNull();\n' % (name_ae))
         jsx_file.write('%s.threeDLayer = true;\n' % name_ae)
         jsx_file.write('%s.source.name = "%s";\n' % (name_ae, name_ae))
-        jsx_file.write('%s.property("position").setValue(%s);\n\n\n' % (name_ae, js_data['bundles_cam'][obj]['position']))
+        jsx_file.write('%s.property("position").setValue(%s);\n\n'
+                       % (name_ae, obj['position']))
+    jsx_file.write('\n')
 
-    # create object bundles (not ready yet)
+    # Create object bundles (not ready yet)
 
-    # create objects (nulls)
-    jsx_file.write('// **************  OBJECTS  **************\n\n\n')
-    for i, obj in enumerate(js_data['nulls']):
-        name_ae = obj
+    # Create objects (nulls)
+    jsx_file.write('// **************  OBJECTS  **************\n\n')
+    for name_ae, obj in js_data['nulls'].items():
         jsx_file.write('var %s = newComp.layers.addNull();\n' % (name_ae))
         jsx_file.write('%s.threeDLayer = true;\n' % name_ae)
         jsx_file.write('%s.source.name = "%s";\n' % (name_ae, name_ae))
-        # Set values of properties, add kyeframes only where needed
-        if include_animation and js_data['nulls'][name_ae]['position_anim']:
-            jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['position']))
-        else:
-            jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['nulls'][obj]['position_static']))
-        if include_animation and js_data['nulls'][name_ae]['orientation_anim']:
-            jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['orientation']))
-        else:
-            jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['nulls'][obj]['orientation_static']))
-        if include_animation and js_data['nulls'][name_ae]['scale_anim']:
-            jsx_file.write('%s.property("scale").setValuesAtTimes([%s],[%s]);\n\n\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['scale']))
-        else:
-            jsx_file.write('%s.property("scale").setValue(%s);\n\n\n' % (name_ae, js_data['nulls'][obj]['scale_static']))
-    # create solids (not ready yet)
-
-    # create lights
-    jsx_file.write('// **************  LIGHTS  **************\n\n\n')
-    for i, obj in enumerate(js_data['lights']):
-        name_ae = obj
-        jsx_file.write('var %s = newComp.layers.addLight("%s", [0.0, 0.0]);\n' % (name_ae, name_ae))
-        jsx_file.write('%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n' % name_ae)
-        # Set values of properties, add kyeframes only where needed
-        if include_animation and js_data['lights'][name_ae]['position_anim']:
-            jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['position']))
-        else:
-            jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['position_static']))
-        if include_animation and js_data['lights'][name_ae]['orientation_anim']:
-            jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['orientation']))
-        else:
-            jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['orientation_static']))
-        if include_animation and js_data['lights'][name_ae]['energy_anim']:
-            jsx_file.write('%s.property("intensity").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['energy']))
-        else:
-            jsx_file.write('%s.property("intensity").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['energy_static']))
-        if include_animation and js_data['lights'][name_ae]['color_anim']:
-            jsx_file.write('%s.property("Color").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['color']))
-        else:
-            jsx_file.write('%s.property("Color").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['color_static']))
-            if js_data['lights'][obj]['type'] == 'SPOT':
-                if include_animation and js_data['lights'][name_ae]['cone_angle_anim']:
-                    jsx_file.write('%s.property("Cone Angle").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['cone_angle']))
-                else:
-                    jsx_file.write('%s.property("Cone Angle").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['cone_angle_static']))
-                if include_animation and js_data['lights'][name_ae]['cone_feather_anim']:
-                    jsx_file.write('%s.property("Cone Feather").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['cone_feather']))
-                else:
-                    jsx_file.write('%s.property("Cone Feather").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['cone_feather_static']))
-        jsx_file.write('\n\n')
-
-    # create cameras
-    jsx_file.write('// **************  CAMERAS  **************\n\n\n')
-    for i, cam in enumerate(js_data['cameras']):  # more than one camera can be selected
-        name_ae = cam
-        jsx_file.write('var %s = newComp.layers.addCamera("%s",[0,0]);\n' % (name_ae, name_ae))
-        jsx_file.write('%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n' % name_ae)
-        # Set values of properties, add kyeframes only where needed
-        if include_animation and js_data['cameras'][name_ae]['position_anim']:
-            jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['position']))
-        else:
-            jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['cameras'][cam]['position_static']))
-        if include_animation and js_data['cameras'][name_ae]['orientation_anim']:
-            jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['orientation']))
-        else:
-            jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['cameras'][cam]['orientation_static']))
-        if include_animation and js_data['cameras'][name_ae]['zoom_anim']:
-            jsx_file.write('%s.property("zoom").setValuesAtTimes([%s],[%s]);\n\n\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['zoom']))
-        else:
-            jsx_file.write('%s.property("zoom").setValue(%s);\n\n\n' % (name_ae, js_data['cameras'][cam]['zoom_static']))
+        # Set values of properties, add keyframes only where needed
+        for prop in ("position", "orientation", "scale"):
+            if include_animation and obj[prop + '_anim']:
+                jsx_file.write(
+                    '%s.property("%s").setValuesAtTimes([%s],[%s]);\n'
+                    % (name_ae, prop, js_data['times'], obj[prop]))
+            else:
+                jsx_file.write(
+                    '%s.property("%s").setValue(%s);\n'
+                    % (name_ae, prop, obj[prop + '_static']))
+        jsx_file.write('\n')
+    jsx_file.write('\n')
+
+    # Create solids
+    jsx_file.write('// **************  SOLIDS  **************\n\n')
+    for name_ae, obj in js_data['solids'].items():
+        jsx_file.write(
+            'var %s = newComp.layers.addSolid(%s,"%s",%i,%i,%f);\n' % (
+                name_ae,
+                obj['color'],
+                name_ae,
+                obj['width'],
+                obj['height'],
+                1.0))
+        jsx_file.write(
+            '%s.threeDLayer = true;\n' % name_ae)
+        jsx_file.write(
+            '%s.source.name = "%s";\n' % (name_ae, name_ae))
+        # Set values of properties, add keyframes only where needed
+        for prop in ("position", "orientation", "scale"):
+            if include_animation and obj[prop + '_anim']:
+                jsx_file.write(
+                    '%s.property("%s").setValuesAtTimes([%s],[%s]);\n'
+                    % (name_ae, prop, js_data['times'], obj[prop]))
+            else:
+                jsx_file.write(
+                    '%s.property("%s").setValue(%s);\n'
+                    % (name_ae, prop, obj[prop + '_static']))
+        jsx_file.write('\n')
+    jsx_file.write('\n')
+
+    # Create images
+    jsx_file.write('// **************  IMAGES  **************\n\n')
+    for name_ae, obj in js_data['images'].items():
+        jsx_file.write(
+            'var newFootage = app.project.importFile(new ImportOptions(File("%s")))\n'
+            % (obj['filepath']))
+        jsx_file.write(
+            'var %s = newComp.layers.add(newFootage);\n' % (name_ae))
+        jsx_file.write(
+            '%s.threeDLayer = true;\n' % name_ae)
+        jsx_file.write(
+            '%s.source.name = "%s";\n' % (name_ae, name_ae))
+        # Set values of properties, add keyframes only where needed
+        for prop in ("position", "orientation", "scale"):
+            if include_animation and obj[prop + '_anim']:
+                jsx_file.write(
+                    '%s.property("%s").setValuesAtTimes([%s],[%s]);\n'
+                    % (name_ae, prop, js_data['times'], obj[prop]))
+            else:
+                jsx_file.write(
+                    '%s.property("%s").setValue(%s);\n'
+                    % (name_ae, prop, obj[prop + '_static']))
+        jsx_file.write('\n')
+    jsx_file.write('\n')
+
+    # Create lights
+    jsx_file.write('// **************  LIGHTS  **************\n\n')
+    for name_ae, obj in js_data['lights'].items():
+        jsx_file.write(
+            'var %s = newComp.layers.addLight("%s", [0.0, 0.0]);\n'
+            % (name_ae, name_ae))
+        jsx_file.write(
+            '%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n'
+            % name_ae)
+        # Set values of properties, add keyframes only where needed
+        props = ["position", "orientation", "intensity", "Color"]
+        if obj['type'] == 'SPOT':
+            props.extend(("Cone Angle", "Cone Feather"))
+        for prop in props:
+            if include_animation and obj[prop + '_anim']:
+                jsx_file.write(
+                    '%s.property("%s").setValuesAtTimes([%s],[%s]);\n'
+                    % (name_ae, prop, js_data['times'], obj[prop]))
+            else:
+                jsx_file.write(
+                    '%s.property("%s").setValue(%s);\n'
+                    % (name_ae, prop, obj[prop + '_static']))
+        jsx_file.write('\n')
+    jsx_file.write('\n')
+
+    # Create cameras
+    jsx_file.write('// **************  CAMERAS  **************\n\n')
+    for name_ae, obj in js_data['cameras'].items():
+        # More than one camera can be selected
+        jsx_file.write(
+            'var %s = newComp.layers.addCamera("%s",[0,0]);\n'
+            % (name_ae, name_ae))
+        jsx_file.write(
+            '%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n'
+            % name_ae)
+
+        # Set values of properties, add keyframes only where needed
+        for prop in ("position", "orientation", "zoom"):
+            if include_animation and obj[prop + '_anim']:
+                jsx_file.write(
+                    '%s.property("%s").setValuesAtTimes([%s],[%s]);\n'
+                    % (name_ae, prop, js_data['times'], obj[prop]))
+            else:
+                jsx_file.write(
+                    '%s.property("%s").setValue(%s);\n'
+                    % (name_ae, prop, obj[prop + '_static']))
+        jsx_file.write('\n')
+    jsx_file.write('\n')
 
     # Exit import if no comp name given
-    jsx_file.write('\n}else{alert ("Exit Import Blender animation data \\nNo Comp\'s name has been chosen","EXIT")};')
+    jsx_file.write('\n}else{alert ("Exit Import Blender animation data \\nNo Comp name has been chosen","EXIT")};')
     # Close function
     jsx_file.write("}\n\n\n")
     # Execute function. Wrap in "undo group" for easy undoing import process
     jsx_file.write('app.beginUndoGroup("Import Blender animation data");\n')
-    jsx_file.write('compFromBlender();\n')  # execute function
+    jsx_file.write('compFromBlender();\n')  # Execute function
     jsx_file.write('app.endUndoGroup();\n\n\n')
     jsx_file.close()
 
-    data['scn'].frame_set(curframe)  # set current frame of animation in blender to state before export
-
-##########################################
-# DO IT
-##########################################
-
+    # Set current frame of animation in blender to state before export
+    data['scn'].frame_set(curframe)
 
-def main(file, context, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles):
-    data = get_comp_data(context)
-    selection = get_selected(context)
-    write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles)
-    print ("\nExport to After Effects Completed")
-    return {'FINISHED'}
 
 ##########################################
 # ExportJsx class register/unregister
 ##########################################
 
+
 from bpy_extras.io_utils import ExportHelper
-from bpy.props import StringProperty, BoolProperty
+from bpy.props import StringProperty, BoolProperty, FloatProperty
 
 
 class ExportJsx(bpy.types.Operator, ExportHelper):
     """Export selected cameras and objects animation to After Effects"""
     bl_idname = "export.jsx"
     bl_label = "Export to Adobe After Effects"
+    bl_options = {'PRESET', 'UNDO'}
     filename_ext = ".jsx"
     filter_glob: StringProperty(default="*.jsx", options={'HIDDEN'})
 
@@ -723,40 +1076,63 @@ class ExportJsx(bpy.types.Operator, ExportHelper):
             description="Include 3D Markers of Camera Motion Solution for selected cameras",
             default=True,
             )
+    include_image_planes: BoolProperty(
+            name="Image Planes",
+            description="Include image mesh objects",
+            default=True,
+            )
 #    include_ob_bundles = BoolProperty(
 #            name="Objects 3D Markers",
 #            description="Include 3D Markers of Object Motion Solution for selected cameras",
 #            default=True,
 #            )
+    ae_size: FloatProperty(
+            name="Scale",
+            description="Size of AE Composition (pixels per 1 BU)",
+            default=100.0,
+            min=0.0,
+            soft_max=10000,
+            )
 
     def draw(self, context):
         layout = self.layout
 
         box = layout.box()
-        box.label(text='Animation:')
-        box.prop(self, 'include_animation')
-        box.label(text='Include Cameras and Objects:')
+        box.label(text='Include Cameras and Objects')
         box.prop(self, 'include_active_cam')
         box.prop(self, 'include_selected_cams')
         box.prop(self, 'include_selected_objects')
-        box.label(text="Include Tracking Data:")
+        box.prop(self, 'include_image_planes')
+        box = layout.box()
+        box.prop(self, 'include_animation')
+        box = layout.box()
+        box.label(text='Transform')
+        box.prop(self, 'ae_size')
+        box = layout.box()
+        box.label(text='Include Tracking Data:')
         box.prop(self, 'include_cam_bundles')
 #        box.prop(self, 'include_ob_bundles')
 
     @classmethod
     def poll(cls, context):
-        active = context.active_object
         selected = context.selected_objects
         camera = context.scene.camera
-        ok = selected or camera
-        return ok
+        return selected or camera
 
     def execute(self, context):
-        return main(self.filepath, context, self.include_animation, self.include_active_cam, self.include_selected_cams, self.include_selected_objects, self.include_cam_bundles)
+        data = get_comp_data(context)
+        selection = get_selected(context)
+        write_jsx_file(self.filepath, data, selection, self.include_animation,
+                       self.include_active_cam, self.include_selected_cams,
+                       self.include_selected_objects, self.include_cam_bundles,
+                       self.include_image_planes, self.ae_size)
+        print("\nExport to After Effects Completed")
+        return {'FINISHED'}
 
 
 def menu_func(self, context):
-    self.layout.operator(ExportJsx.bl_idname, text="Adobe After Effects (.jsx)")
+    self.layout.operator(
+        ExportJsx.bl_idname, text="Adobe After Effects (.jsx)")
 
 
 def register():
@@ -768,5 +1144,6 @@ def unregister():
     bpy.utils.unregister_class(ExportJsx)
     bpy.types.TOPBAR_MT_file_export.remove(menu_func)
 
+
 if __name__ == "__main__":
     register()