Animated Netflix logo for application splash screen

I'm a big fan of the 2019 Netflix logo animation.

I was curious if I could pull off something similar for an Android app. It could be a slick launch animation compared to the static app logo we typically see for apps. The first portion of the animation in particular felt like it would be straight-forward to implement.

I didn't want to use a pre-baked gif/movie or an animation library like Lottie because I was worried about the performance. This is the cold launch screen so it needs to be quick to load. That meant I was off to the world of animated vector drawables.

SVG Logo asset

First off, I needed a vector asset to animate. The logo itself isn't too complicated and I could make a reasonable facsimile in Figma but, as luck would have it, Netflix has a set of public assets available here.

With a Netflix-blessed svg asset in hand, I don't have to worry about reproducing the subtle curves and shadows myself. So far so good, right? Well, unfortunately, there's an issue with the asset file. It's huge! If you're curious to see the svg source, right-click on the logo above and select "Open in new tab". In the new tab, right-click the image and select "View page source". This will show you the text representation of the asset file.

Why is the size a problem? Vector assets are rasterized at runtime which means a slight performance hit vs simply loading a raster asset.

This svg is 40KB which is quite large for a vector asset. Looking at the source code, I see that there are far more paths objects than I would have expected. I then opened the file in Figma to see if I can ascertain what these paths are for.

Zooming in shows that colour-banding is being used to simulate shadow gradients on the lower sections. This explains some of the extra paths but there are still more paths than expected. Enabling Outline mode in Figma reveals the source of the extra paths:

Enabling Outline mode reveals that the shadow bands are broken into various segments
The top and bottom corners have a surprising amount of segments

Well, that's certainly curious. I can't imagine any reason for breaking the bands up like this. I even found a pair of adjacent bands that had the same fill colour applied.

SVG Surgery

So how can we clean this asset up? I decided on two courses of action:

1) Merge paths that comprise a single shadow band into a single path
2) Remove the extra shadow detail at the top-left and bottom-right corners. The animation will be quick enough that their absence won't be noticeable.

Post-operative results

Vector comparison: Original svg on left, reduced version on right
Resulting image comparison: Original on left, reduced version on right
Original New
Number of paths 103 11
File size ~40 KB ~5 KB

Success! We've reduced the path count by a large margin with minimal changes to the visual appearance.

Special thanks to the Figma plugin system
I was able to quickly write a plug-in to traverse a selection, removing any fills and adding a simple black stroke. This allowed me to create the mock-up illustrating the outlines above. For anyone curious, this is the plugin code I used:

function removeFills(node: SceneNode) {
  const strokeColor: SolidPaint = {
    type: "SOLID",
    color: {r:0, g: 0, b: 0},
    opacity: 1
  }
  const strokeWidth = 1;

  if ('fills' in node) {
    node.fills = [];
  }

  if ('strokes' in node) {
    node.strokes = [strokeColor];
    node.strokeWeight = strokeWidth;
  }

  if ('children' in node) {
    node.children.forEach(child => {
      removeFills(child);
    });
  }
}

const selection = figma.currentPage.selection;

selection.forEach(node => {
  removeFills(node);
});
Figma plugin code to remove fills and add a 1px, black stroke

Animate the vector

I'm looking to mimic the way the N can be drawn as a single pen stroke. The animation can be broken down into 3 phases:

1) Reveal the left vertical section with an upwards wipe
2) Reveal the diagonal section with a wipe angled towards the bottom, right corner
3) Reveal the right vertical section with an upwards wipe

In order to achieve this, I converted the svg to an android vector drawable xml file and edited it to create a group for each section. I then created a clip-path in each group that overlays the section, right_clip, diag_clip, and left_clip. Finally, I added animations targeting those clip-paths:

<target android:name="right_clip">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:propertyName="pathData"
            android:duration="250"
            android:valueFrom="M 0 1200 L 237 1200 L 237 1200 L 0 1200 Z"
            android:valueTo="M 0 1200 L 237 1200 L 237 0 L 0 0 Z"
            android:valueType="pathType"
            android:interpolator="@android:anim/accelerate_interpolator"/>
    </aapt:attr>
</target>

<target android:name="diag_clip">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:propertyName="pathData"
            android:startOffset="250"
            android:duration="250"
            android:valueFrom="M 0 0 L 661 0 L 661 0 L 0 0 Z"
            android:valueTo="M 0 0 L 661 0 L 661 1201 L 0 1201 Z"
            android:valueType="pathType"
            android:interpolator="@android:anim/linear_interpolator"/>
    </aapt:attr>
</target>

<target android:name="left_clip">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:propertyName="pathData"
            android:startOffset="500"
            android:duration="250"
            android:valueFrom="M 0 1201 L 661 1201 L 661 1201 L 0 1201 Z"
            android:valueTo="M 0 0 L 661 0 L 661 1201 L 0 1201 Z"
            android:valueType="pathType"
            android:interpolator="@android:anim/linear_interpolator"/>
    </aapt:attr>
</target>
Animation portion of the Android Vector Drawable XML file

I used an accelerating interpolator for the first section and a linear interpolator for the subsequent 2 sections. The first gives the animation a smooth start and the latter gives the animation a snappy feel vs a decelerating interpolator that would slow down at the end.

Time for the Splash screen

It is a fairly straight-forward process so I won't go too much into the details here. The gist of it is:

  1. Create a new Theme (e.g Theme.App.Starting) and set its parent to Theme.SplashScreen or Theme.SplashScreen.IconBackground
  2. In your manifest, set the theme attribute of the whole <application> or just the starting <activity> to Theme.App.Starting
  3. In the onCreate method the starting activity, call [installSplashScreen](https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen#(android.app.Activity).installSplashScreen()) just before super.onCreate(). You also need to make sure that postSplashScreenTheme is set to the application's theme. Alternatively, this call can be replaced by Activity#setTheme if a [SplashScreen](https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen) instance isn't needed.

^ Taken from the google docs here.

Final results

Here's a quick recording of the results:

0:00
/

Not bad! You'll notice I added a section to the main page of the app to view the animation at a larger size. This just let me test the animation more easily than having to constantly close and restart the app.

Thanks for reading!