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

@dimacrossbow/target-zone-react-native

v0.1.0

Published

React Native (Expo) components for @dimacrossbow/target-zone-core — Skia-rendered targets, zones, shots, with pan / pinch / double-tap gestures.

Readme

@dimacrossbow/target-zone-react-native

React Native (Expo) renderer for @dimacrossbow/target-zone-core. Renders targets, scoring zones and shots with @shopify/react-native-skia, and drives the camera (pan / pinch / double-tap zoom) and tap events with react-native-gesture-handler

PIXI is web/WebGL-only, so it can't run in React Native. This package reuses the PIXI-free domain layer of core (@dimacrossbow/target-zone-core/domain — entities, models, events) and re-implements only the rendering and input layers natively.

Status

Implemented: target backdrop image, zones (SVG paths with cut-out holes, accurate hit-testing, and highlight fill), shots (image + color-tinted mask, or geometry), decoration layers with Circle / Image / Text / Path asset nodes, camera pan / pinch / double-tap-to-zoom with Maps-style fit + pan clamp, and surface / zone / shot tap events.

This brings the renderer to feature parity with the web (@dimacrossbow/target-zone-vue) build's component surface, in a data-driven form (you pass target + layers data rather than declaring child components).

Known differences from the web build (paradigm, not gaps):

  • No hover/pointer events on zones or assets — touch input is tap-based, so there is no pointer-over/pointer-out. Zone highlights are shown statically for any zone that declares a highlight (toggle with highlightZones).
  • No declarative child components (<TargetLayer><CircleAsset/></TargetLayer>) — layers and assets are passed as plain data (see below).
  • TextNode honors a common subset of PIXI's TextStyle (fontFamily, fontSize, fill, fontWeight, fontStyle).
  • Undo/redo history is app-level (drive the core entities yourself), as on web.

Install

npm install @dimacrossbow/target-zone-react-native @dimacrossbow/target-zone-core

Then install the native peer dependencies in your app:

npx expo install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated

Add reanimated's Babel plugin last in babel.config.js:

plugins: ['react-native-reanimated/plugin'];

Skia + reanimated + gesture-handler require a custom dev client (not Expo Go): npx expo run:android / run:ios, or build a dev client with EAS.

Usage

Render under a GestureHandlerRootView at the app root:

import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { TargetCanvas, type ITargetData } from '@dimacrossbow/target-zone-react-native';

const target: ITargetData = {
  x: 0, y: 0, width: 320, height: 320,
  image: 'https://example.com/target.png', // or require('./assets/target.png')
  zones: [
    { name: 'bullseye', geometry: 'M 160,160 m -38,0 a 38,38 0 1,0 76,0 a 38,38 0 1,0 -76,0', data: { score: 10 } },
  ],
  shots: [],
};

export default function App() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <TargetCanvas
        target={target}
        width={360}
        height={640}
        doubleTapZoom={2}
        onSurfaceTap={(point, zone) => {
          // point is target-local; zone is the zone under the tap (or null)
        }}
        onShotTap={(shot) => {/* inspect / remove */}}
        onZoneTap={(zone) => {/* … */}}
      />
    </GestureHandlerRootView>
  );
}

A runnable Expo demo lives in ../react-native-example.

Props

| Prop | Default | Notes | | --- | --- | --- | | target | — | ITargetData or a Target entity. Memoize it to avoid rebuilds. | | width / height | — | Canvas size in px. | | backgroundColor | '#202020' | Color behind the world. | | minZoom / maxZoom | 0.1 / 8 | Zoom clamp. | | doubleTapZoom | 2 | Double-tap zoom factor toward the tapped point; <= 1 disables. | | fit | true | object-fit: contain to the target rect (auto fit + pan clamp). | | debugZones | false | Draw zone shapes in a debug color (otherwise hit-test only). | | highlightZones | true | Fill zones that declare a highlight with their configured color. | | layers | [] | Decoration layers (Circle/Image/Text/Path assets). See below. | | onSurfaceTap / onZoneTap / onShotTap / onCameraChange | — | Event callbacks. |

Decoration layers

Pass layers to render Circle / Image / Text / Path assets in target-local mm space — the data-driven counterpart of @dimacrossbow/target-zone-vue's <TargetLayer> + asset components. Colors are numeric 0xRRGGBB, as in core/vue.

import { TargetCanvas, type ILayerData } from '@dimacrossbow/target-zone-react-native';

const layers: ILayerData[] = [
  {
    name: 'hull',
    zIndex: -1, // < 0 → behind the target backdrop; >= 0 → in front
    assets: [
      { kind: 'path', geometry: 'M 10,10 L 90,20 L 50,80 Z',
        fill: { color: 0x33aaff, alpha: 0.15 }, stroke: { color: 0x33aaff, width: 2 } },
    ],
  },
  {
    name: 'markers',
    zIndex: 1000,
    assets: [
      { kind: 'circle', x: 160, y: 160, radius: 4, color: 0xffffff,
        stroke: { color: 0x000000, width: 1 } },
      { kind: 'text', x: 8, y: 8, text: 'Shots: 3', anchor: { x: 0, y: 0 },
        style: { fontSize: 16, fill: 0xffffff, fontWeight: 'bold' } },
      { kind: 'image', x: 300, y: 8, image: 'https://…/logo.png',
        width: 48, height: 48, anchor: { x: 1, y: 0 } },
    ],
  },
];

<TargetCanvas target={target} layers={layers} width={360} height={640} />

Each asset node shares x / y / rotation / alpha / visible and maps to a core/vue primitive:

| kind | vue component | Key fields | | --- | --- | --- | | circle | CircleAsset | radius, color, stroke? | | image | ImageAsset | image, width?, height?, anchor? | | text | TextAsset | text, style?, anchor? | | path | PathAsset | geometry, holes?, fill?, stroke? |

The node components (CircleNode, ImageNode, TextNode, PathNode, AssetNode, LayerNode) and the colorToCss helper are exported for custom renderers.

Event semantics mirror the web build: a shot tap fires onShotTap only; a tap inside a zone fires onZoneTap and onSurfaceTap (with the zone); a tap on empty surface fires onSurfaceTap with zone = null.

Notes

  • This package ships TypeScript source (no build step) so the consuming app's Babel handles the reanimated worklets. @dimacrossbow/target-zone-core/domain is consumed as a prebuilt PIXI-free bundle.
  • pixi.js is a dev-only dependency, present purely so core's .d.ts types resolve. It is never bundled into your app.

License

MIT © dimacrossbow