# Animated Charts as Native Figma Prototypes
_August 18, 2026 · 11 min read · by Systergon_
> Every animated chart in a design review is a video — untouchable, unclickable, impossible to hand over as anything more useful than “like that, but ours”. Figma Charts produces a component set whose variants are wired with Figma’s own prototype interactions instead. Covers the snapshot model, why Smart Animate works on bars and refuses on lines (and the layer-name mechanism behind both), the eleven easings and which ones quietly misreport your data, per-step triggers, and what you actually get on the canvas.
Tags: Figma, Charts, Prototyping, Motion, Plugin
URL: https://systergon.com/blog/figma-charts-animated-charts-native-figma-prototypes
---
[Install Figma Charts — it’s free to try →](https://www.figma.com/community/plugin/1345221583582136577/figma-charts) [Read the help centre →](https://systergon.com/figma-charts/help)

Every animated chart in a design review is a video. Someone recorded a screen, trimmed it, dropped it into the deck — and now the thing being reviewed cannot be clicked, cannot be paused on the frame anyone wants to discuss, cannot be dropped into the prototype next to the screen it belongs to, and cannot be handed to an engineer as anything more useful than “like that, but ours”.

Figma Charts does not produce a video. It produces a **component set whose variants are wired to each other with Figma’s own prototype interactions** — the same thing you would get by building the states by hand and connecting them in the Prototype panel, except the states are real charts and you did not draw them.

Which means the animation behaves like everything else in your file: you can rewire it, retime it, drop it into a bigger flow as an instance, and hand it over as a design rather than a recording.

![The Animation tab in Figma Charts with animation mode off, showing an Enable button and a How it works list: enable animation mode, capture snapshots of chart data states, configure transitions and triggers, insert to create a component set with prototype interactions, then play the prototype in Figma](https://systergon.com/figma-charts-help/animation-panel-light.webp)

## First — get the plugin

Everything below happens inside **Figma Charts**, a Figma plugin. It runs the real JavaScript charting libraries — Google Charts, Highcharts, D3-based Nivo, ApexCharts and Apache ECharts — inside the plugin window, so each state you capture is the library’s own rendering rather than a drawing of one.

[Install Figma Charts from the Figma Community →](https://www.figma.com/community/plugin/1345221583582136577/figma-charts)

Press **⌘/** (**Ctrl /** on Windows), type _Figma Charts_, hit Enter, and open any chart. The **Animation** tab sits between Data and Export.

## The model: snapshots, not keyframes

This is the part to understand before touching anything, because it is not the model most animation tools use.

You do not animate properties over time. You capture **snapshots** — complete states of the chart — and then describe how each one becomes the next. A snapshot holds the chart’s data and any option overrides, so “2023” and “2024” are two snapshots, and so are “before the campaign” and “after the campaign”.

The workflow is therefore:

1. Press **Enable** on the Animation tab to turn animation mode on.
2. Capture a snapshot of the chart as it looks now.
3. Change something — the data, a colour, a chart setting — and capture another.
4. Set how each snapshot transitions to the next.
5. Insert.

**You need at least two.** A single snapshot has nothing to animate between, and the animation export will tell you so rather than producing an empty file. You can have up to **twenty**, which is far more than any chart animation should need.

Each snapshot carries a **label**, and that label is not cosmetic: it becomes the variant name in Figma, written as `State=2023`. So the component set arrives with a real **State** property in the properties panel, and anyone placing an instance can pick which state to show from a dropdown — without touching the prototype at all. Name your snapshots the way you would name variants, because that is what they become.

The consequence of the snapshot model is a discipline worth adopting early: **change one thing between snapshots**. Snapshots capture the whole chart, so two states that differ in data _and_ palette _and_ chart type produce a transition where three things happen at once and none of them reads. If you want the bars to grow and then the colour to shift, that is three snapshots, not two.

## Smart animate, and why it refuses to help sometimes

There are eight transitions, and in practice two of them matter: **Smart animate** and **Dissolve**. The rest — Scroll animate, Push, and the Move and Slide pairs — are Figma’s standard set, useful for moving between two charts as slides rather than for animating one chart’s data.

**Smart animate** matches layers between two states by name and interpolates them. It is what makes bars grow, points travel and a gauge needle sweep. It is also the reason animated charts sometimes look broken for no apparent reason, and the explanation is entirely mechanical:

**Smart animate can only interpolate shapes that correspond.** A bar is a rectangle in both states, so Figma can tween its height. A line is a single path whose point list differs between states — different number of points, different coordinates, no correspondence — so there is nothing to tween. Figma does the only thing it can and swaps one path for the other, which reads as a flicker.

The plugin knows this per chart type, and marks its choice **(Recommended)** in the transition list:

- **Smart animate** — **bar** and **column** (rectangles animate height), **scatter** and **bubble** (points animate position and size), **gauge** (the needle animates rotation), **treemap** (rectangles animate size and position), **funnel** (sections animate width), **radial bar** (arc length) and **heatmap** (cells animate colour).
- **Dissolve** — **line**, **area** and **spline** (paths cannot morph between different data points), **pie** and **donut** (segments cannot morph angles), **radar** (polygon paths are complex), and **Sankey** and **chord** (flow paths and ribbons cannot morph).

Nine and eight. The dividing line is not aesthetic — it is whether the SVG the library produced contains shapes that can be put in correspondence. Fighting it does not work; a line chart set to Smart animate does not draw itself, it stutters.

**What to do instead for a line chart:** animate something that is a shape. Cross-fade the line with Dissolve while a Smart-animated marker travels along it, or build the reveal as a sequence of snapshots with progressively more data points and accept the cross-fade between them. Both read better than a stuttering path.

## Why this works at all — the layer-name trick

It is worth a short detour into the mechanism, because it explains both why the plugin can do this and why the obvious do-it-yourself version does not work.

When Figma imports an SVG it uses each element’s **id** attribute as the layer name. And Smart Animate matches layers between two frames **by name**. Put those together and you get the requirement: for a bar in state one to tween into the corresponding bar in state two, both must arrive in Figma with the same layer name.

Chart libraries do not cooperate with that. They re-render from scratch on every data change and emit whatever ids they like — usually none, sometimes ones seeded from values that just changed. Export two states of a Highcharts bar chart by hand and Smart Animate has nothing to match: every layer in the second frame is, as far as Figma is concerned, a different object that has appeared from nowhere.

So the plugin post-processes the SVG before handing it to Figma, assigning **deterministic ids** to chart elements so they line up across states. It does this per library, because each one marks up its output differently — a bar is `.highcharts-point rect` in one and `.apexcharts-bar-series rect` in another — and it classifies elements semantically as bars, slices, points, lines, areas, gridlines, axis labels and legend labels, then names them by position within their series.

Two practical consequences fall out of that:

- **Correspondence is positional.** The third bar becomes the third bar. If your second snapshot has a different number of categories, some bars have no partner and will appear or vanish rather than move — which is fine when that is the story, and confusing when it is not. Keep the categories stable and animate the values.
- **Renaming layers in Figma afterwards breaks the tween.** The names are the mechanism, not decoration. Tidy up the layer panel after your last insert, not before.

## Duration, easing and the default that is usually right

The default transition is **Smart animate, 800ms, Ease out**, and it is a good default for the reason all good motion defaults are good: it starts fast and settles, which reads as physical.

Duration runs from **100ms to 3000ms**. For data animation the useful range is narrower than that suggests. Under about 300ms the eye cannot follow a bar to its new height and the change registers as a jump; over about 1200ms the viewer has finished reading before the motion has finished happening, and it starts to feel like waiting.

There are eleven easings, and they are Figma’s own:

- **Linear**, **Ease in**, **Ease out**, **Ease in and out** — the standard set.
- **Ease in back**, **Ease out back**, **Ease in and out back** — overshooting curves.
- **Gentle**, **Quick**, **Bouncy**, **Slow** — Figma’s preset curves.

A caution specific to charts: **the overshooting curves lie**. Ease out back and Bouncy carry a bar past its target and settle back, which means for a few frames the chart displays a value that is not in the data. On a marketing animation nobody cares. On a chart in a product, where the whole point is that the height means the number, it is a small dishonesty that a careful viewer will notice. Save the overshoot for entrances, where nothing is being misread — the bars arriving from zero — and keep the data-to-data transitions on Ease out.

## Triggers — who drives it

Every step gets a trigger, and the choice decides whether you have built a playing animation or an interactive one.

The default is **After delay** at 800ms, which makes the whole thing play by itself as soon as you press Present — the right default, because that is what people expect an animated chart to do.

The others are Figma’s own set: **On click**, **While hovering**, **While pressing**, **On drag**, the four mouse triggers (**Mouse enter**, **Mouse leave**, **Mouse down**, **Mouse up**) and two media triggers.

Two are worth reaching for deliberately:

- **On click** turns the chart into a stepper. Useful for a narrative — “here is Q1; click; here is what happened in Q2” — and much better in a live review than a video someone has to scrub.
- **While hovering** reverts when the pointer leaves, which makes a genuine before-and-after comparison: hold to see the projection, release to see today. That is a real interaction pattern you can test on people, not a picture of one.

Triggers can be set per step, so a chart can auto-play its first transition and then wait for a click on the second.

## Checking it before you insert

The Animation tab has its own timeline and transport, so you do not have to insert to find out whether the timing works. Snapshots appear as cards along a timeline with a playhead; **play and pause** run the sequence in the plugin window, and a **speed** control at 0.5×, 1×, 1.5× and 2× lets you slow a transition down to see what it is actually doing.

Slowing to 0.5× is the single most useful habit here. At full speed a Smart Animate that is secretly cross-fading looks approximately fine; at half speed you can see that the bars are not moving, they are dissolving — which tells you the correspondence broke and the categories changed between snapshots.

Transitions and triggers can be set **per step** as well as globally, so a four-snapshot sequence can auto-play the first two steps, wait for a click on the third, and use a different easing on the last. The panel shows which steps are using the default and which are overridden.

**Looping** is on by default: the last variant wires back to the first, so the animation runs continuously in Present. Turn it off when the sequence tells a story with an ending — a build-up to a final state that should stay on screen is ruined by snapping back to the beginning.

## What you actually get on the canvas

Press **+ Insert Animated** and the plugin renders each snapshot, turns each one into a component, and combines them into a **component set** named after your chart with **[Animated]** after it. Then it wires a prototype reaction from each variant to the next, looping back to the first if looping is on.

That output is the whole argument of this post, so it is worth being precise about what it buys you:

- **It is a component set**, so it can be dropped into a screen as an _instance_. The animated chart goes inside the dashboard mockup rather than beside it.
- **The variants are real frames** containing real chart layers, so you can open one and restyle it, or point another flow at it.
- **The interactions are ordinary Figma reactions.** Everything is visible in the Prototype panel and editable there — retime a step, change a trigger, delete a connection — without going back to the plugin.
- **Press _Present_** and it plays, in the same prototype window as the rest of your work, shareable with the same link.

Nothing about it is a black box, which is the difference between a plugin output you can build on and one you have to redo whenever anything changes.

## Letting the AI sequence it

On the Animation tab there is an **AI Generate Animation** button, and what sits behind it is narrower and more useful than “AI makes an animation”: an agent that builds the _timeline_ — the snapshots, the transitions, the triggers, the timing and the per-state overrides — from a description of what you want to show.

It is most useful for the fiddly part rather than the creative part. Describing “step through the four quarters, pause on the last one” and getting a four-snapshot timeline with sensible per-step triggers back is a good use of it; it applies the same Smart-animate-versus-Dissolve rules the transition list recommends, so it will not hand you a line chart set to morph.

Two requirements worth stating: the AI features need a paid plan **and your own API key** — you choose Claude, OpenAI or Gemini in AI settings and paste a key from that provider. The plugin has no model of its own; it talks to your account, so the cost and the data stay yours. If you have not set a key up, the button is there and the feature is not.

## And when you do need a video after all

Sometimes the destination genuinely is a video — a release tweet, a slide for people who will never open Figma. The **Export** tab handles that: **Animation Export** produces a **GIF** (universal support) or a **WEBM** (smaller files), with **FPS** at 15, 24 or 30, a quality setting, a loop count where **0 means infinite**, and an output size.

![The Animation Export section of the Export tab: GIF and WEBM format buttons, FPS at 15, 24 or 30, quality and loop-count fields, an output size of 800 by 600, and a note that at least two animation states are needed in the Animation tab](https://systergon.com/blog/figma-charts-animated-charts-native-figma-prototypes/images/animation-export-crop.webp)

It requires at least two animation states captured on the Animation tab, which is the same requirement as the prototype and a reminder that the snapshots are the source of truth. Build the prototype first; the video falls out of it.

Animation export is PRO, as is the Animation tab itself.

## The limits, stated plainly

Four things this does not do, worth knowing before you plan around it:

- **It is not a runtime animation.** The variants are pre-rendered pictures of chart states, so the animation cannot respond to data that changes after you inserted it. It is a design artefact, not a component that animates in production. If engineering needs the built chart to animate, that is the charting library’s own animation config — which the [Config export](https://systergon.com/blog/figma-charts-export-react-vue-svelte-angular-design-tokens#config) carries.
- **Tooltips and hover states do not come across**, because a Figma layer is a drawing. Anything interactive in the animation has to be built as another snapshot with its own trigger.
- **Twenty snapshots is the ceiling**, and the practical ceiling is much lower. Every snapshot is a full component with a complete chart inside it, so a twenty-state animation is twenty copies of your chart’s layer tree in the file.
- **Reopening to edit means recapturing.** Change the chart after inserting and the existing variants do not update themselves — the snapshots were captured, not linked.

None of that argues against the approach. It argues for capturing the animation once the design has settled, rather than treating it as something you maintain alongside the chart.

## What this is actually good for

Four cases where an animated chart earns its keep, rather than being motion for its own sake:

- **Showing change over time** without a time axis. A bar chart that steps through four quarters uses the whole plot area for four categories instead of squeezing sixteen bars into it.
- **Before and after.** Two states and a hover trigger is the clearest way to show what a change did — and far more honest than two charts side by side with different y-axes.
- **Loading and empty states.** Snapshot the skeleton, snapshot the loaded chart, Smart animate between them. That is a real spec for engineering, not a note saying “chart animates in”.
- **Explaining a chart nobody has seen before.** A Sankey or a treemap is much easier to read if it assembles — and since those are Dissolve types, build it as three or four snapshots that add detail rather than one transition that morphs.

And one case where it does not: **a dashboard mockup that will be screenshotted for a spec**. If the deliverable is a still, the animation is work nobody will see. Capture it when the motion is the thing being decided, not by default.

## A first animation, end to end

1. Open a **bar chart** — the friendliest type, because rectangles Smart animate cleanly.
2. **Animation** tab → **Enable**. Capture a snapshot.
3. Go to **Data**, change the numbers to your second period, come back and capture again.
4. Leave the transition on **Smart animate, 800ms, Ease out**. Leave the trigger on **After delay**.
5. **+ Insert Animated**, then **Present**.
6. Now change one thing and see what it does — set the trigger to **On click**, or the easing to **Bouncy**, and watch the bars overshoot their own values. That is the fastest way to develop a feel for which settings are honest.

The whole thing takes about five minutes, and at the end of it you have something you can hand to an engineer, drop into a prototype, and click — instead of a recording of something you used to have.

[Install Figma Charts — it’s free to try →](https://www.figma.com/community/plugin/1345221583582136577/figma-charts) [From Figma to code →](https://systergon.com/blog/figma-charts-export-react-vue-svelte-angular-design-tokens)