Skip to main content

NeoPopScoreMeter

A semi-circular arc gauge drawn on a Skia Canvas. The filled stroke animates from oldReading to reading using Reanimated withTiming + useDerivedValue, producing a smooth sweep with no JS-thread involvement.

The arc spans 180° (left → right). Score range maps linearly to arc fill percentage: lowerLimit = 0 %, upperLimit = 100 %.

Dark mode

import { NeoPopScoreMeter } from '@codecollab.co/neopop-rn';

<NeoPopScoreMeter
reading={720}
oldReading={0}
type="excellent"
scoreDesc="Great score!"
lowerLimit={300}
upperLimit={900}
showLegends
showIndicators
/>

Light mode with colorConfig override

<NeoPopScoreMeter
reading={480}
oldReading={300}
type="average"
scoreDesc="Room to improve"
lowerLimit={300}
upperLimit={900}
colorConfig={{
trackColor: '#E0E0E0',
scoreTextColor: '#0D0D0D',
descTextColor: '#555555',
}}
/>

Auto-type (derived from reading ratio)

If type is omitted, the stroke color is auto-derived from the score's position in the range: bottom third → poor, middle third → average, top third → excellent.

<NeoPopScoreMeter
reading={reading}
oldReading={prevReading}
lowerLimit={300}
upperLimit={900}
onAnimationComplete={() => console.log('sweep done')}
/>

Props

PropTypeDefaultDescription
readingnumberRequired. Current score value (target of the animation).
oldReadingnumberRequired. Previous score — arc animates from here to reading.
type'excellent' | 'average' | 'poor'autoOverrides stroke color. If omitted, color is derived from the score ratio.
scoreDescstringOptional description shown below the numeric score.
showIndicatorsbooleantrueWhether to show the dot at the arc tip.
showLegendsbooleantrueWhether to show the Poor / Average / Excellent legend row.
lowerLimitnumber300Minimum score value (maps to 0 % arc fill).
upperLimitnumber900Maximum score value (maps to 100 % arc fill).
sizenumber220Width of the canvas (height is half + stroke overhang).
strokeWidthnumber14Stroke width of both the track and the filled arc.
colorMode'dark' | 'light'from providerColor mode override.
colorConfigNeoPopScoreMeterColorConfigPer-instance color overrides (see below).
onAnimationComplete() => voidCalled when the sweep animation finishes.
styleStyleProp<ViewStyle>Extra styles applied to the outer container.

colorConfig

KeyTypeDefaultDescription
excellentColorstringSEMANTIC_SUCCESS[4] (#06C270)Stroke color for excellent readings.
averageColorstring#F5A623Stroke color for average readings.
poorColorstringSEMANTIC_ERROR[4] (#EE4D37)Stroke color for poor readings.
trackColorstring#3D3D3DBackground arc track color.
indicatorColorstring#ffffffColor of the dot indicator at the arc tip.
scoreTextColorstring#ffffffColor of the numeric score label.
descTextColorstring#8A8A8AColor of the scoreDesc label.

Notes

  • Requires @shopify/react-native-skia >= 1.0.0 and react-native-reanimated >= 3.0.0.
  • Uses useDerivedValue to derive a SkPath shared value on the UI thread — no bridge calls per frame.
  • The canvas height is automatically size / 2 + strokeWidth + 4 to display only the top half of the circle.
  • onAnimationComplete is marshalled from the UI thread to the JS thread via runOnJS.