●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
React Native Skia in Rork — Custom Charts, Animations, and Shader Effects
A complete guide to implementing high-quality custom graphics in your Rork app using React Native Skia. Covers Canvas-based custom charts, gradients, shader effects, and interactive animations with Reanimated — all with practical, production-ready code.
Scroll a category page on the App Store and the apps that stop your thumb share one trait: they simply look better than what sits around them.
Standard React Native components tend to produce UIs that look, frankly, pretty similar to each other. Native engineers writing Swift or Kotlin can craft visuals that feel like a completely different tier of quality. Until recently, bridging that gap from a JavaScript-first environment was painful.
React Native Skia changes that. Powered by Google's battle-tested 2D graphics engine used in Chrome and Flutter, it lets you drive the same GPU-level rendering pipeline directly from your Rork app via a Canvas API. That means:
Fully custom charts (line, bar, donut) designed pixel-for-pixel to match your brand
Gradients, blur, shadow, and glow effects that feel silky and native
GLSL-style shader programs via Skia Shader Language (SL) for visual effects impossible in standard RN
Butter-smooth interactive animations when paired with React Native Reanimated
This guide walks you from installation all the way through production-grade implementation patterns and performance tuning, with copy-paste-ready TypeScript throughout.
Prerequisites and Setup
Who This Article Is For
This is an advanced guide. You should be comfortable with:
React Native components and styling fundamentals
TypeScript generics and interface definitions
Building and running apps with Rork Max (Expo-based)
Installing the Required Packages
# Install Skia via Expo CLI to get the correct compatible versionnpx expo install @shopify/react-native-skia# Install Reanimated for interactive animations (highly recommended)npx expo install react-native-reanimated
Always use npx expo install rather than plain npm install. Expo's package resolver picks the version that matches your current SDK, avoiding hard-to-debug version mismatches.
Configuring metro.config.js
When using Reanimated alongside Skia, add the Babel plugin:
// babel.config.jsmodule.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], plugins: [ 'react-native-reanimated/plugin', // Must be last ], };};
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Build custom charts, gradient effects, and shader animations step by step — from Skia basics to full app integration
✦Combine Skia with Reanimated to create fluid interactive animations that make your app stand out from the competition
✦Learn performance best practices and avoid the common pitfalls that cause FPS drops in graphics-heavy React Native apps
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Before jumping into patterns, it's worth internalizing Skia's mental model: you draw by stacking drawing instructions onto a Canvas — similar to HTML Canvas or SVG, but executed entirely on the GPU thread.
Basic Canvas Drawing
import { Canvas, Circle, Paint, Rect } from '@shopify/react-native-skia';export default function BasicSkiaDemo() { return ( // Canvas defines the drawable area <Canvas style={{ width: 300, height: 300 }}> {/* Background fill */} <Rect x={0} y={0} width={300} height={300} color="#1a1a2e" /> {/* Filled circle */} <Circle cx={150} cy={150} r={80} color="#e94560" /> {/* Stroke-only circle using Paint */} <Circle cx={150} cy={150} r={80}> <Paint color="white" style="stroke" strokeWidth={3} /> </Circle> </Canvas> );}
Expected output: A deep-navy background with a red circle outlined in white.
The Paint Component
Paint defines how a shape is drawn — color, stroke width, blend mode, filters, etc.
Expected output: A purple line chart with a gradient fade-out beneath it — the kind of chart you see in polished fintech or health apps.
If you'd prefer a faster path to standard charts without the custom implementation overhead, check out Building Interactive Charts and Graphs in Rork Apps — A Practical Victory Native Guide. Skia is the right choice when design differentiation matters; Victory Native is the right choice when you just need data on screen quickly.
Combining Skia with Reanimated unlocks the full spectrum of interactive animation. If you're new to Reanimated, Rork × React Native Reanimated & Gesture Handler — Building 60fps Animations and Advanced Gesture Interactions is the recommended primer before diving into this section. Skia renders on the GPU thread; Reanimated drives values on the UI thread. Together, they let you build 60–120fps animations without touching the JavaScript thread at all.
Expected output: A smooth 1.2-second animation that fills the ring from 0% to whatever progress value you pass in.
Pattern 4: Shader Effects with Skia Shader Language (SL)
Skia Shader Language is a GLSL-like language that runs pixel-by-pixel on the GPU. It's the key to effects that are completely impossible with standard React Native: animated noise, fluid simulations, procedural textures, and more.
const noiseShaderSource = Skia.RuntimeEffect.Make(` uniform float time; uniform float2 resolution; float hash(float2 p) { p = fract(p * float2(234.34, 435.345)); p += dot(p, p + 34.23); return fract(p.x * p.y); } float noise(float2 p) { float2 i = floor(p); float2 f = fract(p); float2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash(i), hash(i + float2(1, 0)), u.x), mix(hash(i + float2(0, 1)), hash(i + float2(1, 1)), u.x), u.y ); } half4 main(float2 pos) { float2 uv = pos / resolution; float n = 0.0; float amplitude = 0.5; float frequency = 3.0; for (int i = 0; i < 5; i++) { n += amplitude * noise(uv * frequency + time * 0.2); amplitude *= 0.5; frequency *= 2.0; } half3 color = mix( half3(0.05, 0.05, 0.15), half3(0.3, 0.1, 0.5), n ); color = mix(color, half3(0.6, 0.3, 0.9), pow(n, 2.0) * 0.5); return half4(color, 1.0); }`);
Performance Best Practices
Skia is fast — but easy to misuse. These are the rules that matter most. For a broader look at performance optimization across your entire Rork app — rendering, memory, bundle size — see The Complete Rork App Performance Optimization Guide.
1. Memoize Your Paths
Regenerating paths on every render is the single most common performance mistake.
// ❌ Bad: path rebuilt every renderfunction BadExample({ data }: { data: number[] }) { const path = Skia.Path.Make(); // Runs on every render // ...}// ✅ Good: memoized, rebuilt only when data changesfunction GoodExample({ data }: { data: number[] }) { const path = useMemo(() => { const p = Skia.Path.Make(); // ... return p; }, [data]); // ...}
2. Keep Canvas Size Minimal
GPU cost scales with Canvas area. Only wrap the region that actually needs custom graphics.
// ❌ Bad: entire screen in one Canvas<Canvas style={{ flex: 1 }}>...</Canvas>// ✅ Good: targeted Canvas<View style={{ flex: 1 }}> <Text>Normal text — no GPU cost</Text> <Canvas style={{ width: 300, height: 200 }}> {/* Only the chart */} </Canvas></View>
3. Keep Animations on the GPU Thread
When animating, use Skia's useValue + runTiming (or the Reanimated bridge) so drawing stays on the GPU thread. Avoid driving Skia sizes/positions from useState or useAnimatedStyle applied to React Native Views — that routes through the JS bridge and risks frame drops.
4. Be Cautious with BlurMask and ImageFilter
Blur and image filters are expensive. Use them on static elements (backgrounds, decorative cards). Applying them to fast-moving animated elements almost always causes visible frame drops on mid-range Android devices.
Pattern 5: Advanced Composition — Clipping, Blending, and Masking
The patterns above cover the most common use cases, but Skia's compositing model goes much deeper. Here are three techniques that frequently appear in production-grade apps.
Circular Image Clip
Clipping is one of the first things developers reach for when building user avatar components. React Native's borderRadius has limitations with certain image formats and animation contexts; Skia's ClipPath is more reliable and composable.
Skia exposes the full set of Porter-Duff compositing operators and additional blend modes. This opens up creative possibilities that would require complex workarounds in standard React Native.
import { Canvas, Rect, Circle, BlendMode, Group, Paint, LinearGradient, vec,} from '@shopify/react-native-skia';// "Multiply" blend mode darkens where two layers overlap// "Screen" lightens — useful for glow effects over dark backgrounds// "Overlay" enhances contrast in mixed areasexport function BlendModeDemo({ width, height }: { width: number; height: number }) { return ( <Canvas style={{ width, height }}> {/* Base layer: gradient background */} <Rect x={0} y={0} width={width} height={height}> <LinearGradient start={vec(0, 0)} end={vec(width, height)} colors={['#1a1a2e', '#16213e']} /> </Rect> {/* Overlay layer with Screen blend mode — creates a glow */} <Group> <Paint blendMode={BlendMode.Screen}> <Circle cx={width * 0.4} cy={height * 0.5} r={100} color="#6366f180" /> </Paint> </Group> <Group> <Paint blendMode={BlendMode.Screen}> <Circle cx={width * 0.6} cy={height * 0.5} r={100} color="#ec489980" /> </Paint> </Group> </Canvas> );}
Expected output: Two translucent circles overlap with a bright Screen-blended intersection, creating a neon glow effect against the dark background — the kind of visual you'd find in a music app or gaming dashboard.
Text on Canvas
While React Native's Text component handles most text rendering, there are scenarios where you want text tightly integrated into a Skia drawing — for example, labels directly on a chart, or text with custom path-following effects.
import { Canvas, Text, matchFont, useFont,} from '@shopify/react-native-skia';export function ChartLabel({ value, x, y }: { value: string; x: number; y: number }) { // Load a font — in Expo, bundle fonts via expo-font first const font = useFont(require('../assets/fonts/Inter-SemiBold.ttf'), 14); if (!font) return null; return ( <Canvas style={{ width: 300, height: 200 }}> {/* ... chart paths ... */} <Text x={x} y={y} text={value} font={font} color="#ffffff" /> </Canvas> );}
Keep in mind that Skia text does not support automatic line wrapping or accessibility features (screen readers). For most body content, continue using React Native's Text component. Reserve Skia text for data labels, tooltips, and decorative elements inside Canvas drawings.
Debugging Skia in Development
Skia issues can be tricky to diagnose because errors often surface as blank Canvas areas rather than thrown exceptions. Here's a systematic approach.
Enable Skia Debug Mode
In development, wrap your Canvas in a try/catch and log render errors:
The most common cause of a blank Canvas (no error thrown) is a path with no points or a zero-dimension rect. Add a debug rect to confirm the Canvas is actually rendering:
<Canvas style={{ width: 300, height: 200 }}> {/* Debug: bright red fill — remove before production */} <Rect x={0} y={0} width={300} height={200} color="red" opacity={0.2} /> {/* Your actual content */} <Path path={yourPath} ... /></Canvas>
If the debug rect appears but your path doesn't, the path itself is the problem. Check that useMemo dependencies are correct and that min/max calculations aren't producing Infinity or NaN.
Error 1: Skia components outside Canvas
Error: Cannot use Skia components outside of a Canvas
All Skia primitives (Circle, Rect, Path, etc.) must be descendants of a Canvas component. There is no exception.
Error 2: RuntimeEffect.Make returns null
Skia.RuntimeEffect.Make(source) returns null on shader compilation failure. Always guard against this:
Real-World Integration: Healthcare and Fitness Apps
Skia shines brightest in dashboards where data needs to feel alive. A weekly step count summary, calorie burn rings, or sleep quality waves all benefit enormously from custom graphics.
React Native Skia is one of the most powerful tools available to Rork Max developers today — and it's still underused precisely because the learning curve feels steep. But as this guide shows, the core patterns are entirely learnable, and the payoff in visual quality is substantial.
To recap what we covered: Canvas fundamentals and the Paint model; custom data charts using generated paths and gradient fills; glassmorphism and multi-layer visual effects; interactive animations by bridging Reanimated with Skia's value system; GPU-level shader effects via Skia Shader Language; and the performance rules that keep everything running smoothly.
Start small — drop a CustomLineChart into your next feature and see how users respond. Once you get a feel for the Canvas mental model, progressively layering in gradients, animations, and eventually shaders will feel natural rather than intimidating.
Share
Thank You for Reading
Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.