Real-Time Charts and Heat Maps at 60fps with Skia
Draw real-time charts and heat maps at 60fps in React Native with Skia and Reanimated: buffering sensor data, Victory Native, pictures and performance.
Full-Stack, Mobile & AI Engineer
Static charts are a solved problem. Live ones are not. A heart-rate line that scrolls smoothly, a pressure map that shifts as someone moves their weight, a price chart updating several times a second: these need 60 frames per second while data keeps arriving, on phones that are also doing everything else.
Skia, combined with Reanimated, is the tool that makes this practical in React Native. This guide covers drawing real-time charts and heat maps with Skia: why it's fast, how to feed it live data without re-rendering React, when to use a chart library like Victory Native, and the performance rules that keep visuals smooth. It draws on building SuraSole Golf's live pressure heat maps at 60fps.
Key takeaways
- React Native Skia draws with the GPU through Google's Skia engine, instead of building charts from hundreds of native views.
- Feed live data through Reanimated shared values, not React state, so drawing updates without re-rendering components.
- Victory Native (the Skia-based version) covers standard charts: lines, bars, areas, with gestures.
- For heat maps and custom visuals, draw directly, recording a picture per frame or using a shader for smooth gradients.
- Render at the display rate: buffer incoming samples and draw the latest state once per frame.
Why Skia for live visuals
A chart built from React Native views (one view per bar or cell) means creating, laying out and updating many native views every time data changes. For a 20 × 40 heat map updating 60 times a second, that's tens of thousands of view updates per second, far beyond what the layout system is built for.
Skia draws everything onto a single canvas using the GPU, the same way games and design tools do. One canvas, one draw call per frame, no layout work. That's why it's the right tool for dense, fast-changing visuals.
Feeding live data without re-rendering
The rule that matters most: don't put streaming data into React state. Every setState re-renders components; at sensor frequencies that's a guaranteed stutter. Instead:
- Receive data (from Bluetooth, WebSockets or sensors) and write the latest values into a buffer.
- Store the current frame in a Reanimated shared value.
- Let Skia read the shared value and redraw on the UI thread.
React components render once; the drawing updates on its own.
Skia vs react-native-svg
react-native-svg renders SVG elements as native views, which is ideal for icons, illustrations, simple static charts and QR codes (libraries such as react-native-qrcode-svg build on it). It works in Expo Go and on the web. The cost appears when a graph has thousands of points or changes many times a second: every element is a view to update. Skia draws everything on the GPU in a single canvas, which is why it wins for live data, heat maps and effects. A practical split: SVG for static graphics, Skia for anything real-time or dense.
Standard charts with Victory Native
For line, bar and area charts, the Skia-based Victory Native gives you a high-level API (CartesianChart with line, bar and area components), gestures for scrubbing and panning, and animations, while drawing everything with Skia. It's the right choice when your chart is a familiar type and you want axes, labels and interactions without building them yourself.
Heat maps and custom visuals
For something like a pressure map, draw directly. One approach is to build a Skia picture from the latest frame inside a derived value, so it's recomputed on the UI thread whenever the data changes:
import { Canvas, Picture, Skia, createPicture } from "@shopify/react-native-skia";
import { useDerivedValue, type SharedValue } from "react-native-reanimated";
const COLS = 12, ROWS = 24, CELL = 12;
export function HeatMap({ frame }: { frame: SharedValue<number[]> }) {
const picture = useDerivedValue(() =>
createPicture((canvas) => {
const paint = Skia.Paint();
const values = frame.value;
for (let i = 0; i < values.length; i++) {
const x = (i % COLS) * CELL;
const y = Math.floor(i / COLS) * CELL;
paint.setColor(Skia.Color(pressureToColor(values[i]))); // e.g. blue -> red
canvas.drawRect(Skia.XYWHRect(x, y, CELL, CELL), paint);
}
})
);
return (
<Canvas style={{ width: COLS * CELL, height: ROWS * CELL }}>
<Picture picture={picture} />
</Canvas>
);
}pressureToColor must be a worklet (marked with the "worklet" directive) because it runs on the UI thread. For smooth, blended maps instead of cells, a Skia runtime shader can interpolate between sensor points on the GPU, which looks better and scales to larger grids.
From the field: For SuraSole Golf I built the mobile app for pressure-sensing smart insoles, streaming plantar-pressure data from both feet over Bluetooth Low Energy and rendering it as live heat maps and weight-shift charts at 60fps, synced frame by frame against captured swing video. That combination, continuous data plus video sync, is exactly where drawing on the GPU and keeping data out of React state pays off.
Performance rules
| Do | Avoid |
|---|---|
| Draw dense visuals in one Skia canvas | One React Native view per data point |
| Keep streaming data in shared values or buffers | setState for every sample |
| Render the latest frame per display refresh | Drawing every incoming sample |
| Reuse paints and paths where possible | Allocating large objects in every frame |
| Downsample long time series before drawing | Drawing 100,000 points on a 400-pixel-wide line |
| Test on mid-range Android devices | Judging smoothness on a simulator |
Syncing visuals with video and time
When charts must line up with something else, such as recorded video or audio, timestamp every data frame at the source and align by time, not by the order frames arrive. Bluetooth and network delivery can bunch up or delay frames, but timestamps let you place each one exactly on the timeline and scrub through both together.
Skia on the web
The Skia library also runs on the web through CanvasKit, Skia compiled to WebAssembly. That means the same chart code can serve a web dashboard, which is useful when a mobile app and a web portal show the same live data. The trade-off is a WebAssembly download that must load before the first draw, so load it early, show a lightweight placeholder, and consider simpler SVG charts for public web pages where load time matters most.
Accessibility for live charts
Canvas drawings are invisible to screen readers. Provide a text summary of what matters ("Weight 60% on left foot", "Heart rate 142, rising") through accessibility labels or a live region, and make sure key values are available outside the chart.
FAQ
What is React Native Skia?
React Native Skia is a library from Shopify that brings Google's Skia graphics engine to React Native. It draws shapes, paths, images, text and shaders on a GPU-accelerated canvas, which makes it ideal for charts, heat maps and custom visual effects.
How do I make real-time charts smooth in React Native?
Draw with Skia, keep incoming data in Reanimated shared values or buffers instead of React state, and redraw once per frame with the latest data. Use Victory Native for standard chart types and draw custom visuals directly on a Skia canvas.
Is Victory Native good for charts in React Native?
Yes. Its Skia-based version provides line, bar and area charts with gestures and animations while rendering with Skia, which makes it fast enough for interactive and frequently updating charts. For heat maps or unusual visuals, draw directly with Skia.
Can React Native handle 60fps data visualisation?
Yes, when rendering happens on the UI thread with Skia and data flows through shared values rather than React state. Dense, live visuals like sensor heat maps can run at 60fps on mid-range devices with this approach.
Next steps
If your app needs live charts, sensor visualisations or custom graphics that stay smooth on real devices, I've built them at 60fps and can help you design yours. Get in touch, or see how I work as a React Native developer.
Sources
- React Native Skia, Shopify
- Victory Native, Nearform
- React Native Reanimated, Software Mansion
- Skia graphics library, Google
Related
60fps Animations with Reanimated: Patterns That Don't Drop Frames
React Native animations at 60fps with Reanimated 4: CSS transitions, gesture-driven motion, scroll effects, layout animations and real-time data visuals.
FlatList vs FlashList vs LegendList: Lists That Don't Stutter
FlatList vs FlashList v2 vs LegendList in 2026: how each renders long lists, when to use which, and the row-level fixes that keep lists smooth.
How We Cut React Native Startup Time from 3.8s to 1.5s
The levers that cut React Native startup time by about 60%: measuring cold start properly, Hermes, image optimisation and cache-first fetching.
