npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-tgfx

v0.0.2-alpha.3

Published

A declarative, Skia-style GPU 2D canvas for React Native, backed by Tencent's tgfx and built with Nitro Modules.

Readme

react-native-tgfx

A declarative, Skia-style GPU 2D canvas for React Native, backed by Tencent's tgfx and built with Nitro Modules.

Render shapes, strokes, paths, gradients, images and text through a React component tree that compiles to a single native draw-program and runs on the GPU (Metal on iOS, OpenGL on Android).

import { Canvas, Rect, Circle, Path, Image, Text, LinearGradient, useImage } from 'react-native-tgfx'

function Hello() {
  const img = useImage(require('./cat.png'))
  return (
    <Canvas style={{ flex: 1 }}>
      <Rect x={0} y={0} width={120} height={80} color="lightblue" />

      <Circle cx={160} cy={120} r={40} color="red" style="stroke" strokeWidth={6} strokeCap="round" />

      <Path path="M0 200 q40 -60 80 0 t80 0" color="#5856D6" style="stroke" strokeWidth={5} />

      <Rect x={0} y={260} width={160} height={70}>
        <LinearGradient start={{ x: 0, y: 260 }} end={{ x: 160, y: 330 }} colors={['#FF6CAB', '#7366FF']} />
      </Rect>

      {img && <Image x={180} y={260} width={96} height={96} image={img} fit="cover" />}

      <Text x={0} y={380} text="Hello tgfx" fontSize={24} color="#111" />
    </Canvas>
  )
}

How it works

<Canvas> children
   │  (custom react-reconciler, persistence mode)
   ▼
immutable node tree ──► JSON draw-program (compiler) ──► `scene` prop
   │
   ▼  Nitro HybridView (TgfxView)
Swift / Kotlin view shell (CAMetalLayer / TextureView)
   │
   ▼  shared C++ engine (nlohmann::json → tgfx::Canvas)
tgfx ──► Metal (iOS) / OpenGL (Android) ──► GPU
  • A dedicated react-reconciler turns the component tree into an immutable scene and compiles it to a compact JSON program on every change.
  • A single Nitro TgfxView receives that program via its scene string prop. The Swift/Kotlin shell only hosts the GPU surface; all drawing is shared C++.
  • Drawing happens on the platform's display-link / choreographer thread.

Components

| Component | Key props | |---|---| | Canvas | style, children | | Group | transform, origin, opacity + inherited paint | | Rect / Oval | x, y, width, height | | RoundedRect | x, y, width, height, r (or rx/ry) | | Circle | cx, cy, r | | Line | x1, y1, x2, y2 | | Path | path (SVG path data) | | Image | x, y, width, height, image (a useImage handle), fit, sampling, rect | | Text | x, y, text, fontSize, fontFamily | | Paint | paint as a child of a shape/group | | LinearGradient / RadialGradient | shader as a child of a shape/Paint |

Paint props (on any drawing component, Group, or Paint): color, style ('fill' | 'stroke'), strokeWidth, strokeCap, strokeJoin, opacity, antiAlias.

Colors accept hex ('#rrggbb', '#rgba'), rgb()/rgba(), common names, or a packed 0xAARRGGBB number.

Hooks

  • useImageState(source) — the same load as useImage, returning { data, error, loading } so a slow load can be told from a failed one
  • useImage(source) — loads a require() asset, URL, data: URI, or base64 string into a native TgfxImage handle. Local files are decoded natively and their bytes never enter JS; nothing is base64-encoded on the JS thread.
  • useVideo(source, { seek, paused, looping, volume }) — plays a video into a drawable handle: { currentFrame, currentTime, duration, framerate, rotation, size }. AVPlayer/MediaPlayer decode, a frame never enters JS as pixels or as a pointer, and frames are pulled on the UI thread, so a busy JS thread does not stall playback. currentFrame is one stable object, owned by the player. Needs Reanimated. See docs/video.md.
  • setImageCacheLimit(bytes) — byte budget for decoded images (64 MB). A decoded image is resident twice, as CPU pixels and as the GPU texture uploaded from them, so this is applied to both the pixel cache and tgfx's context cache.

Requirements

  • React Native 0.78+ with the New Architecture (Nitro Views are Fabric-only)
  • iOS: Xcode 16.4+, Metal; Android: NDK 27+, compileSdk 34+, OpenGL

Install (monorepo / local)

tgfx is a git submodule built from source.

git submodule update --init --recursive
# fetch tgfx's third_party (depsync) — see scripts/
cd packages/react-native-tgfx/cpp/third_party/tgfx && depsync

Both platforms link tgfx as a prebuilt static lib (npm installs ship it; a git checkout builds it once):

bash packages/react-native-tgfx/scripts/build-tgfx-ios.sh       # device + simulator slices
bash packages/react-native-tgfx/scripts/build-tgfx-android.sh   # all 4 ABIs, or pass a subset

On-device rendering tests

Rendering is verified with React Native Harness image snapshots, which mount a real <Canvas> in the example app and screenshot it — no app navigation and no UI selectors.

cd apps/example
npx react-native run-android          # rebuild once after adding @react-native-harness/ui
npx react-native-harness --harnessRunner android-emulator

Tests live in apps/example/src/*.harness.tsx; baselines land in apps/example/src/__image_snapshots__/<runner>/. Runners are declared in apps/example/rn-harness.config.mjs.

android-emulator is the authoritative runner. It targets the Pixel_8_API_35 AVD, which anyone can recreate, so a diff there is a rendering change rather than a different phone. Review that set as the source of truth.

The android runner (motorola moto g35 5G) is advisory: real GPU and real driver, but its baselines only ever match that one phone. GPU, density and anti-aliasing all move pixels, so a diff there on another device is not a regression — check the emulator before believing it.

Never delete a baseline to "fix" a failure. A missing baseline is written on the spot and reported as a pass, so a checkout with no baselines passes without comparing anything. Regenerate deliberately: delete the file, re-run, then open the new PNG and confirm it is actually correct before committing it.

Snapshot targets must use composite="texture": a screenshot draws the view tree into a bitmap, and a composite="layer" canvas lives on its own compositor layer where nothing can see it.

License

MIT — wraps tgfx (BSD-3-Clause) and Nitro (MIT).