Features
What AE2CSS turns into web code — and what's next.
What exports today, what's partial, what's coming — and exactly where any JavaScript shows up, and where it doesn't.
Shape morphing, Glow, Drop Shadow, luma mattes and particle systems all export. Those are Lottie's limits, not CSS's — the FAQ at the bottom takes each one in turn.
Support matrix
Everything in your comp, accounted for.
Better to know the edges up front than hit them mid-project.
Motion & timing
| Expression-driven motion | Supported | Wiggle, loops, time-driven spin — the expression is evaluated and rewritten as clean CSS keys. No parsing, no per-frame JavaScript. |
|---|---|---|
| Position, Scale, Rotation, Opacity | Supported | Real keyframes with per-segment cubic-bezier easing — pixel-matched to After Effects, never a stack of baked frames. |
| Animated Anchor Point | Supported | A keyframed anchor moves the pivot, not the layer — so rotation and scale keep turning around the point as it travels, the way After Effects does it. |
| Auto-Orient along path | Supported | A layer that turns to follow its motion path rides offset-rotate: auto where the position is a real path — zero extra keyframes — and a baked tangent where it isn't. Angles are unwrapped, so 170°→−170° never spins back through zero. |
| Auto-range loops | Supported | Finds the real animated window so every layer loops tight and on one shared beat. |
| Time Remapping | Partial | A precomp After Effects loops on a shorter period keeps that period: its contents get their own CSS clock instead of the same cycle copied N times over. Time Remap on a top-level layer is reported, not replayed. |
| Motion blur | Not in CSS | Per-frame smear has no CSS equivalent, and faking it with stacked copies costs more than it buys. The export tells you the layer had it rather than dropping it quietly. |
Effects
| Glow | Supported | Vector-first: blur → filter: blur(), AE Glow → a drop-shadow stack, round glows → a radial bloom. A flattened PNG only as a last resort. |
|---|---|---|
| Echo | Supported | AE's Echo becomes time-shifted, fading clones — generalized over any animation, not a per-case hack. |
| Light sweep / shine | Supported | Both routes: a matte shine band, solid or gradient, riding real keyframe motion — and AE's own CC Light Sweep, whose band is rebuilt from the effect's own parameters. Edge Intensity and Thickness (the rim glint) are reported rather than drawn. |
| Draw-on strokes / Trim | Supported | Animated trim start, end and offset draw the stroke on along its path. |
| Layer blend modes | Supported | Multiply, Screen, Overlay, Soft and Hard Light, Lighten, Add and Linear Dodge become mix-blend-mode on the layer — inside precomps too. Stencil and Silhouette are read as track mattes on everything beneath. The modes CSS has no analogue for fall back to Normal and say so. |
| Layer Styles | Supported | Drop Shadow and Outer Glow → drop-shadow(); Stroke, Inner Glow and Inner Shadow → box-shadow; Color Overlay goes through the same recolor path as a Fill effect — applied after the effect stack, as After Effects composites them. Bevel, Satin and the gradient/pattern overlays are reported. |
| Colour correction | Partial | Hue/Saturation, Brightness & Contrast, Invert and Drop Shadow compile into one static filter: chain, in AE's own effect order. CSS filter can't animate on the compositor, so a keyframed parameter holds its first value and says so. Levels, Curves, Lumetri and friends are reported instead of silently approximated. |
| Adjustment layers | Supported | Fill recolor and glow apply straight to each layer beneath, per-target — no wrapper, no repaint. |
| Transform effect | Partial | Reads as one static matrix plus an opacity multiplier, with expression-driven controllers resolved to their values. Keyframing the effect's own parameters exports the in-point pose and reports the rest. |
| Gradient Ramp | Partial | Rides the layer's own alpha as a real CSS gradient — a circle stays a circle — across rects, ellipses, donuts, groups and pen paths alike. On a solid or footage layer, and for a ramp that animates, it falls back and reports. |
| Path morph — affine | Supported | Square→diamond and rotate/scale/skew morphs become pure CSS transform: matrix() — compositor-only. Sample density is measured against the pose After Effects draws, not guessed from an angle. |
| Path morph — true shape change | Supported | Genuine contour changes (e.g. a blob) render via a tiny canvas runtime, scoped to the morphing path — see "What ships" below. Everything else on the layer stays CSS on the compositor. |
| Radial Wipe | Supported | The loading-pie reveal: an angular clip-path cut from the layer's own alpha, with Transition Completion animating it. CSS allows one clip per element, so a layer carrying both a wipe and a light sweep keeps the wipe and reports the dropped sweep. |
| Linear Wipe / Venetian Blinds | Incoming | The same shape of problem — an effect that decides which part of the layer you see — with no reader yet, so the layer exports fully painted and, unlike the rest of this table, without a warning. Radial Wipe just left that state; these follow. |
Masking & mattes
| Single mask & track matte | Supported | Every matte mode including inverted — vector clip-path or a baked alpha mask. |
|---|---|---|
| Animated track matte | Supported | The "bar wipes a banner open" rig: a matte whose rect or ellipse path is keyframed exports as a real animated clip — no baked asset, crisp at any size. Content that moves under a static matte gets the matte pinned in comp space instead, so the shape travels through it as in After Effects. |
| Pathfinder / Merge Paths | Supported | Add, Subtract, Intersect and Difference, all live vector and all animating. Union and Difference are one clip-path; Subtract and Intersect become a chain of wrappers, one per cutter, so two overlapping cutters compose exactly as After Effects composites them instead of cancelling each other out. Only a radial-gradient merge still bakes. |
| Feather, Expansion & the harder mask modes | Partial | On a layer mask (not to be confused with Merge Paths above), Feather, Expansion, Intersect and Difference bake the layer's alpha to a mask image — right pixels, one frame. Mask Opacity below 100% isn't read yet: the mask applies fully opaque. |
| Multi-mask compositing | Partial | One active mask is live vector. More than one falls back to that same baked alpha mask — correct, but a single frame — except on a solid, where Add plus Subtract still composite as real vector. Stacking masks as live mask-composite layers is the next step. |
| Animated mask path | Partial | An animated mask on a solid drives real geometry — a keyframed circle, or the same morph machinery a shape path uses. Animating clip-path on any layer is designed but deliberately unshipped: it repaints on the main thread, so it will land scoped to constant-vertex paths. |
Images, precomps & nesting
| Smart image baking | Supported | Anything too dense for code — thick effect stacks, video, a whole precomp — bakes down to a single crisp image and ships. Everything vectors can reach stays code. |
|---|---|---|
| Nested precomps, any depth | Supported | A precomp inside a precomp inside a precomp: every level keeps its own transform, paint order and opacity, and each container clips to the nested comp's bounds exactly as After Effects rasterizes it. |
| Collapse Transformations | Supported | A collapsed precomp exports instead of being refused — the switch lifts the clip, as in After Effects. |
| Looped precomp | Supported | A precomp looped through Time Remapping runs its contents on their own CSS clock, at their real period — not the same cycle copied across the master timeline. |
| Image layers (PNG / JPG / WebP) | Supported | Copied as-is, or rendered when effects or video are applied. |
| Image + glow / blur | Supported | Baked to a crisp PNG; CSS animates the layer over it. |
| Image precomp — Bake | Supported | The whole precomp becomes one image; the host layer's transforms animate. |
| Image precomp — Div / per-asset | Supported | Each inner image becomes its own <img>, animated separately. |
| Master Properties / Essential Graphics | Incoming | Overrides set on the precomp layer aren't read yet — the export uses the source comp's own values and reports the difference. |
Systems & advanced
| Native text layers | Supported | Real, selectable, searchable HTML text — never a raster. Font, weight, size, tracking, leading and alignment come across, with a Google Fonts import for mapped families and a system stack for the rest. Per-character Text Animators — typewriter, fly-up — ride the first Range Selector and share the loop. Not yet: animated Source Text, text on a path, text stroke. |
|---|---|---|
| Particle systems | Supported | Authored in our Particle Lab, exported as native CSS: each particle is a DOM node driven by pure CSS keyframes — fast, GPU-friendly, glow included. One small scoped module spawns them — no canvas, no generic engine. |
| Repeater | Supported | Each copy becomes a real clone of the layer carrying its own accumulated matrix — so it inherits the paint, masks, morphs and the layer's own animation for free. Compounding scale and rotation come out exact. Clamped at 40 copies, with a warning. |
| 3D transforms | Partial | Per-layer 3D rotation, Orientation, Z-depth and AE's default perspective, emitted only when the scene truly goes 3D. |
| Cameras & lights | Incoming | A comp with an animated camera exports as though the default camera never moved. Real camera and light rigs, with depth sorting, arrive with the full 3D scene. |
| Puppet / mesh warp | Incoming | The core already finds the mesh and its pins, but true mesh deformation is a WebGL path — not representable as CSS — and it isn't wired into the panel yet. |
| Number count-up / odometer | Incoming | The render is settled: a compositor-safe digit-strip measured at zero paints per second, against 421 for the naive version. What's left is reading the intent back out of After Effects, which doesn't count natively. |
Shapes & paths
| Rectangles | Supported | Fill, gradient, stroke and corner radius — animated, including a keyframed Size or Roundness. |
|---|---|---|
| Ellipses & circles | Supported | Fill, gradient and stroke; true round corners. An animated Path Position rides a compositor-only translate(). |
| Stars & polygons | Supported | Synthesized into a real contour, roundness included, then handed to the same readers a pen path uses — so animated radii, rotation and position ride the morph path for free. Animating the number of points changes the vertex count, so the star holds its first pose. |
| Donuts & rings | Supported | Including a keyframed (animated) hole radius. |
| Custom pen paths | Supported | Arbitrary bezier shapes as inline SVG — fill, gradient and stroke. A path that is really a rect or an ellipse is recognized and shipped as a CSS box instead. |
| Shapes from Text | Supported | Per-letter and per-group transforms, staggered reveals. |
| Shape-group transforms | Partial | A group's own Position, Scale, Rotation and Opacity animate — including the one-group case a spinner's orbiting dot is built from, which used to export complete, correctly painted and motionless. What's still frozen is a sub-group nested inside another group: its transform is composed once at its in-point. |
| Shape path operators | Incoming | Offset Paths, Round Corners, Pucker & Bloat, Twist, Zig Zag and Wiggle Paths aren't read — a layer using one exports its undistorted contour. Outline the shape in After Effects if you need one today. |
| Dashed strokes | Incoming | stroke-dasharray is a direct translation and it's on the list — dashes, line join, miter and taper aren't read yet. |
Fills & color
| Solid & animated fill | Supported | Color and color-over-time, as native CSS. A Fill, Tint or Color Control effect wins over the source colour, with expression links resolved. |
|---|---|---|
| Gradients — linear & radial | Supported | Sampled pixel-accurate from After Effects; radial on ellipses, donuts and pen paths. |
| Transparent / alpha gradients | Supported | Alpha-aware sampling, emitted as rgba() stops. |
| Animated gradient colours | Partial | The gradient's geometry animates, but its stops are sampled from After Effects once, so the colours hold — After Effects gives a script no readable value for Gradient Colors. Highlight Length and Angle aren't read. |
What ships
What lands in your export — and what never does.
Your animation becomes the page, not a payload it loads.
Zero runtime, by default
Shapes, gradients, masks, transforms, easing, affine morphs and images all export as plain HTML and CSS. No JavaScript, no JSON, no player to download or parse. The CSS is the animation.
A tiny runtime, only for two effects
Two things genuinely can't be pure CSS: particle systems and true shape-morphing (a real contour change, not a rotate or scale). Those ship one small, purpose-built animation-runtime.js — a few kilobytes scoped to that effect. Not a generic interpreter, not a Lottie-style player — and omitted entirely when your comp uses neither.
your-export/ animation.html ← semantic markup, minimal DOM animation.css ← every transform, gradient & keyframe — pure CSS animation-runtime.js ← OPTIONAL — only if you used particles or true morph images/ ← baked PNG/JPG assets, when needed masks/ ← baked alpha masks, when a mask needs one
JSON only lives in our tooling — the Particle Lab manifest you author against, plus dev diagnostics. It never leaves After Effects: nothing JSON-shaped, and no generic player, is written to your export.
FAQ
The five things people assume can't be done.
Every one of them is a real limit of Lottie, and it gets repeated about CSS export by association. Here's where AE2CSS actually stands.
Does AE2CSS support shape morphing?
transform: matrix() on the compositor, with no JavaScript at all. A genuine contour change — a blob wobbling, vertices moving independently — is drawn by a small canvas runtime scoped to that path alone, while every other layer stays CSS. The one condition is a constant point count: a path that gains or loses a vertex mid-animation is held static.Does it export Glow and Drop Shadow?
box-shadow bloom whose colour model was matched against real AE renders; a blurred glow copy becomes filter: blur(); Drop Shadow becomes filter: drop-shadow() with its offset, softness, colour and opacity. It stays crisp at any zoom and a developer can recolour it in one line. Fill, Tint, Hue/Saturation, Brightness & Contrast and Invert map to CSS filters the same way.Does it support luma mattes and track mattes?
clip-path; where it doesn't — feathered, gradient or luminance-driven — the matte layer is rendered to a real alpha mask and applied with CSS mask-image. Nothing about a luma matte forces a video or a flattened frame.Does it support particle systems?
Does the CSS get too long and unreadable on a big animation?
@keyframes collapse into one block, values shared by several elements are lifted into a single /* Shared values */ rule, empty wrapper <div>s are folded away, and each keyframe has to earn its place against what After Effects actually draws. Our heaviest reference scene — 96 layers at 1920×1080 — is 48 KB of CSS, about 7 KB gzipped, with a legend at the top and every block commented with the layer it came from.So what does it genuinely not export?
Don't see your animation?
The motion it can't read yet is our roadmap. Flag it in one click from inside After Effects — the most-requested gaps get built first and arrive through the updater.