> ## Documentation Index
> Fetch the complete documentation index at: https://react-native-livechart.brandtnewlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Types

> Exported TypeScript types — data shapes, config objects, and the palette.

All types are exported from the package root:

```tsx theme={null}
import type {
  CandleGap,
  CandleGapsConfig,
  ChartGap,
  ChartGapsConfig,
  LiveChartHandle,
  LiveChartFrameStats,
  LiveChartPoint,
  ReferenceLine,
  SeriesConfig,
} from "react-native-livechart";
import type { SharedValue } from "react-native-reanimated";
```

The source `.d.ts` and JSDoc remain the canonical reference (your editor surfaces them on hover);
the most-used shapes are reproduced here.

## Data

```ts theme={null}
type CanvasMode = "transparent" | "opaque";
```

`CanvasMode` controls whether the Skia canvas participates in transparent composition or owns its
background. On Android, opaque mode selects SurfaceView. See
[Android surface rendering](/guides/android-surface-rendering).

```ts theme={null}
interface LiveChartPoint {
  time: number;  // unix seconds
  value: number;
}

interface CandlePoint {
  time: number;  // bucket start, unix seconds
  open: number;
  high: number;
  low: number;
  close: number;
  volume?: number; // optional traded volume; drives the volume bars (candle mode)
}

type CandleGapKind = "no-trades" | "unavailable" | "unknown";

interface CandleGap {
  from: number; // inclusive, unix seconds
  to: number;   // exclusive, unix seconds
  kind: CandleGapKind;
  label?: string;
}

// Renderer-neutral aliases used by lineGaps. The candle names remain available.
type ChartGapKind = CandleGapKind;
type ChartGap = CandleGap;

interface SeriesConfig {
  id: string;
  data: LiveChartPoint[];
  value: number;            // latest live value
  color?: string;
  label?: string;
  visible?: boolean;        // default true
  style?: "solid" | "dashed";
  intervals?: [number, number];
  curve?: "monotone" | "linear"; // interpolation; default "monotone"
  simplify?: number;          // per-series path tolerance in px; inherits line.simplify
  strokeWidth?: number;
  glow?: boolean;
  kind?: "outcome" | "derived";
  valueLabel?: string;
}
```

Both chart components also accept this shared plotted-data opacity control:

```ts theme={null}
interface LiveChartCoreProps {
  // UI-thread value from 0 (hidden) to 1 (fully visible); default 1.
  seriesOpacity?: SharedValue<number>;
}
```

`seriesOpacity` dims plot data (line and area fill, candles, value lines, badges,
and inline values) without dimming axes, legends, reference lines, or scrub UI.
While it is below `1`, live dots and pulse rings fade completely out so a dimmed
stroke cannot show through them; they return once the multiplier reaches `1`.
See [Line & area](/guides/line-and-area#dimming-replacement-data) or
[Multi-series](/guides/multi-series#dimming-replacement-data).

The experimental frame-loop controls are available on `LiveChart`:

```ts theme={null}
interface LiveChartFrameStats {
  frames: number;    // active engine callbacks
  published: number; // callbacks that changed a tracked engine value
  skipped: number;   // callbacks whose tracked engine values were unchanged
}

interface LiveChartProps {
  autoSleep?: boolean; // experimental; default false; single-series only
  isFrameLoopActive?: SharedValue<boolean>;
  debugFrameStats?: SharedValue<LiveChartFrameStats>;
}
```

See [Scroll interaction](/guides/scroll-interaction) for the parent-scroll gate
and the counter's measurement limits.

## Momentum

```ts theme={null}
type Momentum = "up" | "down" | "flat";

interface MomentumConfig {
  threshold?: number; // default 0.12
  lookback?: number;  // default 20
}
```

## Annotations

```ts theme={null}
type MarkerKind = "trade" | "boost" | "graduation" | "winner" | "clawback";

interface Marker {
  id: string;
  time: number;        // unix seconds
  kind: MarkerKind;
  seriesId?: string;   // anchor to a series line (multi-series)
  value?: number;      // absolute y (takes precedence over seriesId)
  color?: string;
  icon?: string;       // text/emoji glyph override
  image?: SkImage;     // image glyph override
  pill?: boolean;      // draw the icon in a filled circular badge
  size?: number;       // default 16
  side?: "above" | "below" | "center"; // sit off the anchor (default "center")
  data?: unknown;      // surfaced on onMarkerPress
}

// Fires on tap (there is no hover on touch); `null` on a miss.
interface MarkerPressEvent {
  marker: Marker;
  point: { x: number; y: number };
  index: number;       // index in the markers array
  isGrouped: boolean;  // true when a collapsed cluster (count badge) was tapped
  members?: Marker[];  // the cluster's markers when isGrouped
}

// Second argument to renderMarker — cluster / position state.
interface MarkerRenderContext {
  index: number;
  isGrouped: boolean;
  groupCount: number;
  side: "above" | "below" | "center";
}

// Object form of the `markerCluster` prop (tunes stacked collision). Passing it
// implies mode: "stacked" unless you set mode explicitly.
interface MarkerClusterConfig {
  mode?: "anchored" | "stacked";
  direction?: "horizontal" | "vertical"; // fan sideways (default) or pile into a column
  overlap?: number;        // 0 (touching) – 1 (stacked); default 0.75
  maxBeforeGroup?: number; // collapse a run past this many; default 5
  maxVisible?: number;     // vertical columns only: keep this many oldest glyphs; default unbounded
  groupBadge?: "count" | "marker" | MarkerGroupBadge; // collapsed look: count circle
                          // (default), the representative marker's own glyph, or a
                          // dedicated custom badge you supply (object form)
  showGroupCount?: boolean; // with a non-count badge, stamp the count in the corner; default false
}
// Badge options for a collapsed cluster. Use letterSpacing by itself to tune the
// built-in count, or add image/icon for a dedicated glyph. @experimental
interface MarkerGroupBadge {
  letterSpacing?: number; // extra px between count digits; default 0
  image?: SkImage; // custom Skia image (precedence over icon)
  icon?: string;   // text/emoji glyph (when image unset)
  color?: string;  // icon / pill color; defaults to a palette accent
  pill?: boolean;  // wrap the icon in a filled circular badge
  size?: number;   // glyph box size in px; default 16
}

interface TradeEvent {
  side: "buy" | "sell";
  price: number;
  size: number;
  time: number;        // unix seconds
  symbol?: string;
}

interface ReferenceLine {
  id?: string;                   // stable identity; supply when lines may reorder
  // Form A — horizontal line:
  value?: number;
  // Form B — time-varying line (sorted unix-second points):
  series?: LiveChartPoint[];
  extendToStart?: boolean;       // flat-extend the first value left; default true
  extendToNow?: boolean;         // flat-extend the last value to live; default true
  // Form C — horizontal band:
  valueFrom?: number;
  valueTo?: number;
  // Form D — vertical time band (unix seconds):
  from?: number;
  to?: number;
  // Shared:
  label?: string;
  strokeWidth?: number;
  intervals?: [number, number];
  color?: string;
  fillColor?: string;            // band fill; defaults to color, then palette refLine
  fillOpacity?: number;          // default 0.16
  strokeOpacity?: number;        // line / series / band-border opacity; default 1
  fullWidth?: boolean;           // span edge-to-edge through the Y-axis gutter (Form A/C);
                                 //   label/badge stay in the plot. default false
  labelColor?: string;
  labelPosition?: "left" | "center" | "right";
  showValue?: boolean;
  excludeFromRange?: boolean;
  // Pill badge for a Form-A line (working orders, alerts, targets) — pinned to an
  // edge with a dashed connector; auto-pins with a chevron when off-screen:
  badge?: boolean | ReferenceLineBadgeConfig;
  badgeBackground?: string;  // fallback for badge.background; default theme tooltipBg
  badgeBorderColor?: string; // fallback for badge.borderColor; default the line color
  badgeRadius?: number;      // fallback for badge.radius; default 5
  // Legacy off-axis badge (prefer `badge`, which also shows in-range + supports an icon):
  offAxisBadge?: boolean;
  offAxisBadgeLabel?: string;
  // Draggable (Form A only) — grab the line and drag it along the Y-axis:
  draggable?: boolean;             // default false
  grabRange?: [number, number];    // canvas x px where a press may grab it; default anywhere
  snap?: number;                   // round the dragged value to this increment
  bounds?: [number, number];       // hard-clamp the draggable value
  onChange?: (value: number) => void;  // during drag (de-duped to value changes)
  onCommit?: (value: number) => void;  // on release — pair with a controlled `value`
  onDragIn?: (value: number) => void;  // value entered the visible range / bounds
  onDragOut?: (value: number) => void; // value left the visible range / hit a bound
}

interface ReferenceLineBadgeConfig {
  position?: "left" | "center" | "right"; // edge to pin to ("center" floats at the
                                          //   value, no connector); default "left"
  icon?: string;               // leading glyph (chart font), like Marker.icon
  text?: boolean;              // show the label/value; default true. false → icon-only
  background?: string;         // falls back to badgeBackground, then theme tooltipBg
  borderColor?: string;        // falls back to badgeBorderColor, then the line color
  borderWidth?: number;        // border stroke width; default 1
  radius?: number;             // corner radius; falls back to badgeRadius, then 5
  textColor?: string;          // label/icon color; falls back to labelColor, then theme
  fontSize?: number;           // badge font size; falls back to the chart font
  fontFamily?: string;         // badge font family; falls back to the chart font
  fontWeight?: FontWeight;     // badge font weight; falls back to the chart font
  offsetX?: number;            // nudge the whole badge from its anchor; default 0
  offsetY?: number;            // nudge the whole badge from its anchor; default 0
}

interface ReferenceLineRenderProps {
  line: ReferenceLine;            // the line being rendered
  index: number;                  // its index in `referenceLines`
  value: SharedValue<number>;     // live Y-axis value (tracks dragging)
  valueStr: SharedValue<string>;  // value formatted with the chart's formatValue
  y: SharedValue<number>;         // canvas Y px of the line (-1 when not laid out)
  inRange: SharedValue<boolean>;  // whether the value is within the visible range
  edge: SharedValue<"above" | "in" | "below">; // for a directional off-axis chevron
  dragging: SharedValue<boolean>; // whether this line is currently being dragged
}

// `renderReferenceLine` replaces a tag in every state. `renderOffAxisReferenceLine`
// keeps the built-in in-range tag and shows the custom element only for edge !== "in".

interface ReferenceLineGroupingConfig {
  // Off-axis badge / offAxisBadge tags group at either plot edge. Hidden plain
  // off-axis lines and custom-rendered tags do not count toward a group.
  radius?: number;             // collapse lines whose value-Y are within this many px; default 18
  badge?: ReferenceLineBadgeConfig;   // count-pill styling (same style/shape config as a
                                      //   per-line badge: position, icon, colors, radius,
                                      //   border, textColor, font, offset)
  format?: (count: number) => string; // label the count, e.g. n => `×${n}`; default String(n)
}

interface ChartSegment {
  from?: number;             // unix seconds; omit → chart's left edge
  to?: number;               // unix seconds; omit → live edge (now)
  // Scrub-focus line styling (the headline interaction):
  recolorLine?: boolean;     // join scrub-focus dimming; default true. false → line
                             //   never dims (divider/label still draw); behaves as a gap
  mutedColor?: string;       // de-emphasis color when NOT focused; default: palette.gridLabel
                             //   (an alpha color, e.g. "rgba(154,160,166,0.4)", fades the line)
  mutedColors?: string[];    // ≥2 → de-emphasis gradient; precedence over mutedColor
  active?: boolean;          // force-focus this segment without scrubbing; default false
  // Divider + label (colors inherit the chart palette — no base color needed):
  divider?: boolean;         // dashed vertical line at `from`; default false
  dividerColor?: string;     // default: palette.refLine
  label?: string;            // caption — shown only with the divider; drawn in palette.refLabel
  labelPosition?: "left" | "right"; // default "left"
}
```

## Scrub payloads

```ts theme={null}
interface ScrubPointCore {
  time: number;
  value: number;
  x: number; // canvas X
  y: number; // canvas Y
}

interface ScrubPoint extends ScrubPointCore {
  candle?: CandlePoint; // candle mode only
  gap?: ChartGap; // line or candle mode, when a bridged declared gap supplies value
}

interface ScrubPointMulti extends ScrubPointCore {
  seriesValues: { id: string; label?: string; value: number }[];
}

// Payload for onScrubAction (order-ticket mode). `price` is the value at the
// reticle Y — a chosen level — not the line value at that time.
interface ScrubActionPoint {
  price: number;        // reticle-Y value, optionally snap-rounded
  time: number;         // unix seconds at the reticle X
  x: number;            // canvas X
  y: number;            // canvas Y
  candle?: CandlePoint; // candle mode only — OHLC under the reticle X (context)
}
```

## Config objects

These are the option shapes accepted by the matching props.

```ts theme={null}
interface CandleGapBridgeStyle {
  color?: string;
  opacity?: number;
  strokeWidth?: number;
  strokeCap?: "butt" | "round" | "square";
}
interface CandleGapBandStyle {
  fillColor?: string;
  fillOpacity?: number;
  borderColor?: string;
  borderOpacity?: number;
  borderWidth?: number;
  intervals?: [number, number];
}
interface CandleGapLabelStyle {
  color?: string;
  position?: "left" | "right";
}
interface CandleGapStyle {
  bridge?: false | CandleGapBridgeStyle;
  band?: false | CandleGapBandStyle;
  label?: false | CandleGapLabelStyle;
}
interface CandleGapsConfig {
  gaps: CandleGap[];
  styles?: Partial<Record<CandleGapKind, CandleGapStyle>>;
}
type ChartGapBridgeStyle = CandleGapBridgeStyle;
type ChartGapBandStyle = CandleGapBandStyle;
type ChartGapLabelStyle = CandleGapLabelStyle;
type ChartGapStyle = CandleGapStyle;
type ChartGapsConfig = CandleGapsConfig;
interface LineConfig {
  width?: number;   // stroke width in px; default 2
  color?: string | SharedValue<string>; // line color override; defaults to palette
                    //   accent. A SharedValue animates the stroke and the built-in
                    //   selection dot on the UI thread; a custom selection dot,
                    //   segment base, area-dot tint, and threshold rest color then
                    //   use the palette line color
  colors?: string[];// per-point gradient stops (left → right); wins over color
  curve?: "monotone" | "linear"; // point interpolation; default "monotone"
                    //   (smooth cubic). "linear" = straight segments / hard-edged.
  simplify?: number; // screen-space path tolerance in px; default 0 (off).
                    //   Removes only intermediate drawn points within the tolerance;
                    //   source data, axis fitting, markers, and scrubbing stay exact.
  join?: "round" | "miter" | "bevel"; // corner join; default "round".
                    //   "miter" = sharp/angular peaks, "bevel" = flattened.
  cap?: "round" | "butt" | "square";  // start/end cap; default "round".
                    //   pair "butt" + join "miter" for a fully hard-edged line.
}
interface GradientConfig {
  topOpacity?: number;    // accent-derived top fill opacity
  bottomOpacity?: number; // accent-derived bottom fill opacity
  colors?: string[] | SharedValue<string[]>; // explicit gradient stops (top →
                          //   bottom), ≥ 2 entries; overrides topOpacity/
                          //   bottomOpacity when provided. A SharedValue animates
                          //   the stops on the UI thread; keep ≥ 2 entries in it
  positions?: number[];   // optional stop positions (0..1, ascending), same
                          //   length as colors; ignored if the lengths differ
                          //   (with animated colors, applied as given)
}
interface AreaDotsConfig {  // dot-lattice fill of the area beneath the line
  spacing?: number; // lattice pitch (px) between dots, both axes; default 12
  size?: number;    // dot diameter (px); default 1.6
  color?: string;   // dot color; omit to derive a faint tint from the line color
  opacity?: number; // overall field opacity (0..1); default 1
}
interface ThresholdConfig {
  // The split value (Y-axis units). A SharedValue<number> for a single live
  // benchmark, OR a LiveChartPoint[] for a time-varying threshold the split,
  // band + marker follow point-for-point (clamps to its first/last value outside
  // its range → flat-extends to the live edge). See the Threshold split guide.
  // Provide value OR series (series wins).
  value?: SharedValue<number> | LiveChartPoint[];
  // LIVE time-varying threshold: like the LiveChartPoint[] form but a
  // SharedValue — .set()/.modify() tracks on the UI thread, no re-render
  // (a VWAP updated every tick). Points sorted by time, like `data`.
  series?: SharedValue<LiveChartPoint[]>;
  aboveColor?: string;        // stroke at/above value; default palette up-green
  belowColor?: string;        // stroke below value;    default palette down-red
  fill?: boolean | { opacity?: number }; // line↔threshold P/L band; default off, opacity 0.16
  includeInRange?: boolean;   // fold the threshold into the Y-range fit (like reference lines); default false
  extendToStart?: boolean;    // series: extend first value flat to the window start; default true
  extendToNow?: boolean;      // series: extend flat past the last point to "now"; default true
  line?: boolean | ThresholdLineConfig; // marker line at value; default off
}
interface ThresholdLineConfig {
  label?: string;                    // label text, e.g. "Break-even"
  labelPosition?: "left" | "right";  // "left" = inside plot (clear of y-axis); default "left"
  labelAnchor?: "first" | "last";    // series: visible left-edge or live/right-edge value; default "last"
  color?: string;                    // line + label color; default palette refLine/refLabel
  labelColor?: string;               // label text color; falls back to color, then palette refLabel
  intervals?: [number, number];      // dash pattern; default [4, 4]
  strokeWidth?: number;              // default 1
  showValue?: boolean;               // append the formatted value to the label; default false
}
interface ThresholdBadgeRenderProps {
  line: ThresholdLineConfig;          // resolved marker-line config
  value: SharedValue<number>;         // live threshold value
  valueStr: SharedValue<string>;      // formatted with the chart's formatValue
  y: SharedValue<number>;             // live canvas Y (NaN when geometry is unavailable)
  visible: SharedValue<boolean>;      // whether the badge is inside the plot
}
interface BadgeConfig {
  variant?: "default" | "minimal";
  tail?: boolean;        // pointed tail toward the dot; false = pill sits flush
                         //   at the gutter edge (no tail space reserved); default true
  background?: string;
  position?: "right" | "left";
  // Shape / style — all Skia-native, drawn in the batched canvas pass (no perf cost):
  radius?: number;          // corner radius (px); default capsule (pillHeight/2), clamped to that max
  borderColor?: string;     // pill border color; default none
  borderWidth?: number;     // border stroke width (px), only drawn with borderColor; default 1
  textColor?: string;       // label text color override; default variant/theme rule
  fontSize?: number;        // badge font size (px); falls back to the chart `font`
  fontFamily?: string;      // badge font family; falls back to the chart `font`
  fontWeight?: FontWeight;  // badge font weight; falls back to the chart `font`
  offsetX?: number;         // nudge the whole badge horizontally (px); default 0
  offsetY?: number;         // nudge the whole badge vertically (px); default 0
  followViewEdge?: boolean; // while time-scrolled, track the price at the visible
                            // window's right edge (badge value/color + value line + dot);
                            // default false
}
interface PulseConfig {
  interval?: number; duration?: number; maxRadius?: number;
  opacity?: number; strokeWidth?: number;
}
interface ValueLineConfig { strokeWidth?: number; intervals?: [number, number]; color?: string }
// Shared styling for a straight line (the connector, valueLine, …). Omit `intervals` for solid.
interface LineStyleConfig { color?: string; strokeWidth?: number; intervals?: [number, number] }
interface ScrubConfig {
  tooltip?: boolean; // existing master tooltip switch; false also suppresses seriesTooltip
  // LiveChartSeries only: opt-in Morfi-style time + per-series value pills.
  // false/omitted preserves the existing guide-only default.
  seriesTooltip?: boolean | PerSeriesTooltipConfig;
  dimTarget?: "future" | "otherCandles"; // default "future"; otherCandles hides the scrub line/dot in candle mode, falls back to future in line mode
  dimOpacity?: number; // opacity of the selected dim target; clamped to [0, 1]; default 0.3
  dimFadeMs?: number; // otherCandles fade-in/out duration; default 60; 0 = instant
  crosshairLineColor?: string; crosshairDimColor?: string; // crosshairDimColor = legacy colored mask
  crosshairStrokeWidth?: number; // line width in px; default 1
  crosshairOvershoot?: number; // extend past top/bottom in px; preserves a custom top-tooltip stop; negatives clamp to 0; default 0
  crosshairFade?: boolean; // fade near the live edge; default true
  crosshairFadeDistance?: number; // visible line/dot/tooltip fade distance in px; negatives clamp to 0; default 4
  crosshairLineCap?: "butt" | "round" | "square"; // omit to preserve the existing Skia default
  crosshairDash?: number[] | boolean; // dash the crosshair line; true = [4,4], or explicit [on, off, …] px
  tooltipBackground?: string; tooltipColor?: string; tooltipBorderColor?: string;
  tooltipBorderRadius?: number; // pill corner radius; default 5
  tooltipPlacement?: "side" | "top" | "bottom" | "point"; // default "side" (offset/flip); top/bottom center over the line; point floats above the scrub dot
  tooltipMargin?: number; // gap (px) to the pinned plot edge (top for side/top, bottom for bottom); default 8
  tooltipShowValue?: boolean; tooltipShowTime?: boolean; // default both true; drop a row (e.g. date-only)
  panGestureDelay?: number; // press-and-hold ms before scrubbing activates; default 0
  clampToPlot?: boolean; // plain scrub: ignore starts beyond the plot's X bounds and clamp active drags; default false
  hideOverlaysOnScrub?: boolean; // fade markers + reference lines out while scrubbing; default false
  snapToCandles?: boolean; // candle mode: snap the crosshair to candle centers (tick-to-tick); gaps between candles + line mode keep the raw X; default false
}
interface PerSeriesTooltipConfig {
  alwaysShow?: boolean;      // pin value pills to visible endpoints while idle; default false
  bucketSeconds?: number;    // omit to infer from the first visible series
  formatSeriesValue?: (value: number, seriesId: string) => string; // UI-thread worklet
  formatTimeRange?: (from: number, to: number) => string;          // UI-thread worklet
  maxLabelChars?: number;    // ellipsis truncation; default 14

  guideColor?: string;
  guideWidth?: number;       // default 1
  guideDashPattern?: boolean | number[]; // default [3,3]; false = solid

  timePillBackground?: string; timePillColor?: string; timePillBorderColor?: string;
  timePillRadius?: number; timePillPaddingX?: number; timePillPaddingY?: number;

  seriesPillBackground?: string;
  seriesPillLabelColor?: string;
  seriesPillValueColor?: string;
  seriesPillBorderColor?: string;
  seriesPillRadius?: number;
  seriesPillPaddingX?: number; seriesPillPaddingY?: number;
  seriesPillDotSize?: number; seriesPillDotGap?: number;
  seriesPillLabelValueGap?: number;
  intersectionDotSize?: number;
}
// Order-ticket mode (scrubAction). Opt-in — default off.
interface ScrubActionConfig {
  icon?: string;       // action-badge glyph; default "+"
  background?: string; // action-badge background; default the accent / badge color
  iconColor?: string;  // icon + price-text color; default the badge text color
  lineColor?: string;  // horizontal level-line color; default palette.crosshairLine
  text?: boolean;      // show the price readout; default true. false → icon-only pill
  timeBadge?: boolean; // date/time pill where the line meets the x-axis; default false
  snap?: number;       // round the reported price to this increment (e.g. 0.01, 0.5)
  dismissOnTapOutside?: boolean; // empty-plot tap dismisses vs. re-places; default false
  dismissOnAction?: boolean;     // dismiss the reticle once the badge fires onScrubAction; default false
}
interface SelectionDotRingConfig {
  color?: string; // ring color, defaults to the dot color
  width?: number; // ring thickness past the dot, default 2
}
// The scrub-intersection dot (selectionDot). Default ON for LiveChart,
// OFF for LiveChartSeries (the crosshair + opt-in per-series tooltip dots mark it).
interface SelectionDotConfig {
  size?: number; // dot radius, default 4
  color?: string; // dot color, defaults to the line / leading-series color
  ring?: boolean | SelectionDotRingConfig; // outer halo, default on
  component?: ComponentType<SelectionDotProps>; // custom Skia dot; ignores size/color/ring
}
interface GridStyleConfig { color?: string; strokeWidth?: number; intervals?: number[]; opacity?: number }
interface YAxisConfig {
  // Label side; reserve left label width with insets.left. Default "right".
  side?: "left" | "right";
  minGap?: number; // min px gap between grid lines; default 36
  // Multiplier used to choose dynamic nice intervals without changing plotted
  // values. Pair with formatValue using the same multiplier. Must be positive
  // and finite; invalid values use 1. Unrepresentable scaled ranges fall back
  // to source-unit intervals. Ignored with count. Default 1.
  intervalScale?: number;
  // Show a fixed number of evenly-spaced prices (top = high, bottom = low)
  // instead of the dynamic nice-interval grid. Values track the live range each
  // frame. `minGap` still floors the spacing; clamped to at most 15. Default 0.
  count?: number;
  // Place labels in a shared left-aligned column whose right edge sits this
  // many px from the canvas edge. Omit for the centered-gutter placement.
  labelRightMargin?: number;
  // Gap between the shared label column and each grid/plain-reference-line end.
  // Only applies with labelRightMargin. Default 0.
  gridEndGap?: number;
  // Float the price axis over a full-width plot instead of reserving a right
  // gutter — the line/candles run to the edge and the labels float on top.
  // Pairs with `timeScroll` (see the Time-scroll guide). Default false. @experimental
  float?: boolean;
}
interface XAxisConfig { minGap?: number } // default 60
// Fades both axes while LiveChart is idle. @experimental
interface AxisAutoHideConfig {
  fadeInMs?: number;    // interaction-start fade duration; default 60
  fadeOutMs?: number;   // fade back to idle; default 250
  idleOpacity?: number; // axes' resting opacity (0 = hidden); default 0
  hideAfterMs?: number; // idle delay before fade-out; default 3000
}
// Volume bars below the candles (candle mode only). Bars normalize to the largest
// visible volume; the candle plot shrinks by `maxHeight` to make room. @see CandlePoint.volume
interface VolumeConfig {
  upColor?: string;    // bars for up (close ≥ open) candles; default palette.candleUp
  downColor?: string;  // bars for down candles; default palette.candleDown
  maxHeight?: number;  // reserved band height (px) = the tallest bar; default 48
  radius?: number;     // bar-top corner radius (px); default 2
  opacity?: number;    // opacity of the whole band (0..1); default 0.6
}
// Horizontal time-scrolling (pan back through history). @experimental
interface TimeScrollConfig {
  gesture?: "holdToScrub" | "axisDrag"; // activation; default "holdToScrub"
  scrubHoldMs?: number; // holdToScrub: press-hold (ms) before scrub engages; default 500
  hideLiveOnScrollBack?: boolean; // hide live badge + dot + value line while scrolled back (they mark the off-screen live price); default true. Ignored with badge.followViewEdge
  overscroll?: number; // fraction of the window (0–1) pan/zoom may travel past the data bounds into blank space (TradingView-style); default 0 (hard stops at the oldest data / live edge)
  fling?: boolean; // keep release momentum after a fast drag; false stops exactly where the finger lifts. Default true.
}
// Tunes the return-to-live glide (the `returnToLive` prop). @experimental
interface ReturnToLiveConfig {
  duration?: number; // glide duration (ms) back to live; default 450 (0 = instant snap)
}
// Tune/disable the built-in transition animations — the object form of `transitions`.
interface TransitionConfig {
  reveal?: number;          // grow-in when data appears, on timeframe change, or candle→line; default 600 (0 = snap)
  mode?: number;            // candle↔line crossfade (single-series LiveChart only); default 300 (0 = snap)
  candleLerpSpeed?: number; // candle-width ease speed (0–1, like smoothing); candle mode; default 0.08 (1 = instant resize)
}
// Styling for the breathing loading shell — the object form of `loading`.
interface LoadingConfig {
  color?: string;          // squiggle + skeleton color; default theme gridLine
  strokeWidth?: number;    // squiggle stroke width; default the chart line strokeWidth
  amplitude?: number;      // base breathing-wave height (px); default 14
  speed?: number;          // breathing-wave speed multiplier; default 1 (0 freezes)
  axisLabels?: boolean;    // draw the skeleton Y-axis placeholders; default true (false = squiggle only)
}
// Pinch-to-zoom the visible time window (two-finger, focal-anchored). @experimental
interface ZoomConfig {
  minTimeWindow?: number; // tightest window in seconds (max zoom-in); default timeWindow / 8
  maxTimeWindow?: number; // widest window in seconds (max zoom-out); default the full data span
}
// Visible window reported by onVisibleRangeChange (unix seconds). @experimental
interface VisibleRange {
  startSec: number;   // left-edge time of the visible window
  endSec: number;     // right-edge time of the visible window
  following: boolean; // true when at the live edge (not scrolled back / paused)
}
// Edge label (topLabel / bottomLabel). Default off — both opt-in.
interface AxisLabelConfig {
  format?: (v: number) => string; // built-in value formatter; defaults to formatValue
  color?: string;                 // text color; defaults to palette.gridLabel (muted)
  // "left"/"right" pin to that edge (default "right"). "extrema" floats the label
  // on the actual high (topLabel) / low (bottomLabel) data point. "extrema-edge"
  // keeps the label on the top/bottom edge (x-aligned) with a dot + connector.
  position?: "left" | "right" | "extrema" | "extrema-edge";
  fontSize?: number;              // built-in value text size (px); default 11
  fontWeight?: FontWeight;        // built-in value text weight; default platform default
  fontFamily?: string;            // built-in value text font family
  dotColor?: string;              // extrema modes — dot color; defaults to color
  dotSize?: number;               // extrema modes — dot diameter (px); default 7
  dot?: boolean;                  // extrema modes — draw the marker dot; default true
  // "extrema-edge" connector (dot → edge label). true = dashed default, false =
  // none, or a LineStyleConfig. Default on (dashed) in "extrema-edge" mode.
  connector?: boolean | LineStyleConfig;
  render?: () => React.ReactElement | null; // custom element; overrides everything above
}
interface ChartInsets { top?: number; right?: number; bottom?: number; left?: number }
interface LeftEdgeFadeConfig { width?: number; startColor?: string; endColor?: string }

interface DotGlowConfig {
  color?: string; // default: resolved dot fill color
  radius?: number; // glow source-circle radius, default 7
  blur?: number; // Skia blur radius, default 5
  opacity?: number; // 0–1, default 0.18
}
interface DotRingConfig {
  color?: string; // default: theme `badgeOuterBg`
  width?: number; // default 2.5
}
// Shared live-dot styling (LiveChart `dot`; LiveChartSeries `dot` extends it)
interface DotConfig {
  radius?: number; // color-filled dot radius, default 3.5
  ring?: boolean | DotRingConfig; // crisp outer backing ring, default true
  glow?: boolean | DotGlowConfig; // soft static glow, default false
  show?: boolean; // @deprecated — prefer dot={false}; default true
  color?: string; // dot fill, defaults to the line color
  trackWhileParked?: boolean; // while scrolled back / overscrolled, the dot tracks the true live point — keeps pulsing, stays visible, hides once the point leaves the window; ignored with badge.followViewEdge (LiveChart only). Default false
}
interface MultiSeriesDotConfig extends DotConfig {
  pulse?: boolean | PulseConfig;
  valueLine?: boolean | ValueLineConfig;
  valueLabel?: boolean;
}
interface LegendConfig {
  visible?: boolean;
  compact?: boolean;
  position?: "top" | "bottom";
  style?: LegendStyle;
}

interface FontConfig {
  fontFamily?: string;      // default "Menlo"
  fontSize?: number;        // default 11
  fontWeight?: FontWeight;
  typeface?: DataSourceParam; // require(...) / path / Uint8Array
  fontManager?: SkFontMgr | null;
}
```

## RangeAnimationConfig

Exported config for the shared `rangeAnimation` prop on `LiveChart` and `LiveChartSeries`.

```ts theme={null}
interface RangeAnimationConfig {
  animateExpansion?: boolean;    // default false; outward bounds snap
  expansionSmoothing?: number;   // inherits smoothing; only used with animateExpansion
  contractionSmoothing?: number; // inherits smoothing
}
```

Speeds are per-60fps-frame fractions of the remaining gap, using frame-rate-independent
exponential easing. Finite overrides clamp to 0..1; non-finite overrides inherit `smoothing`.
While the fitted and displayed ranges do not overlap, contraction is limited to the
animated expansion speed so the bounds cannot cross.
`smoothing: 1`, explicit snaps, static mode, and active manual Y-scale dragging take precedence.
Axis-label fades remain under `metrics.grid`. See
[Y-range animation](/guides/y-range-scale#animating-automatic-range-changes).

## Imperative handle

`LiveChart` and `LiveChartSeries` accept a ref with the same exported handle:

```ts theme={null}
interface LiveChartHandle {
  // Reset built-in pinch zoom to timeWindow and clear its focal offset so the
  // chart follows the live edge again. Safe when already reset.
  resetZoom(): void;
}
```

Use `useRef<LiveChartHandle>(null)` and pass the ref to either chart. A paused chart remains paused.
See [Time-scroll → Reset zoom from a button](/guides/time-scroll#reset-zoom-from-a-button).

## AxisLabelConfig

Shape for the `topLabel` / `bottomLabel` props. Both are opt-in (default off).
With `true`, the chart floats its current top (`topLabel`) / bottom
(`bottomLabel`) Y-axis bound at that edge, formatted with `format` (falling back
to the chart's `formatValue`) in `color` (falling back to the muted
`palette.gridLabel`), aligned by `position`. The values track the live Y-axis
range each frame on the UI thread. Set `render` to float a fully custom element
at the edge instead of the built-in value. `position: "extrema"` instead floats
the label (a dot + value, or your `render` element) at the actual data point
where the high / low occurs, tracking it as the chart scrolls. See
[Axis labels](/guides/axes-and-grid#axis-edge-labels) and
[Marking the extrema points](/guides/extrema-labels).

## SelectionDotProps

Props passed to a custom `selectionDot.component` — the dot drawn at the scrub
intersection. Every positional input is a `SharedValue`, so the dot animates on
the UI thread without re-renders.

```ts theme={null}
interface SelectionDotProps {
  x: SharedValue<number>;       // scrub X in canvas px
  y: SharedValue<number>;       // scrub Y (line / value intersection)
  active: SharedValue<boolean>; // whether scrubbing is active
  opacity: SharedValue<number>; // crosshair fade opacity (0..1), already ramped
  color: string;                // resolved dot color (line / series accent)
  size: number;                 // suggested dot radius in px
}
```

## TooltipRenderProps

Context passed to a custom `renderTooltip` — the fully custom scrub tooltip. The element you
return is a React Native view the chart floats over
the canvas and positions on the UI thread (per `scrub.tooltipPlacement`). Every live field is a
`SharedValue`, so bind them to animated text (e.g. an `Animated.createAnimatedComponent(TextInput)`
driven by `useAnimatedProps`) and both movement **and** text stay on the UI thread — no JS
re-render while scrubbing. See [Custom tooltip](/guides/scrubbing#custom-tooltip-rendertooltip).

```ts theme={null}
interface TooltipRenderProps {
  value: SharedValue<number | null>; // value under the crosshair (candle mode: the close)
  time: SharedValue<number>;         // window time (unix seconds) under the crosshair
  valueStr: SharedValue<string>;     // value formatted with the chart's formatValue
  timeStr: SharedValue<string>;      // time formatted with the chart's formatTime
  active: SharedValue<boolean>;      // whether scrubbing is active
  // Candle mode: the OHLC bucket under the crosshair (null in line mode / inactive).
  candle: SharedValue<CandlePoint | null>;
  // Line or candle mode: the declared gap under the crosshair (null otherwise).
  gap: SharedValue<ChartGap | null>;
}
```

## ChartOverlayContext

The price↔pixel / time↔pixel bridge passed to a custom
[`renderOverlay`](/api-reference/livechart#renderoverlay) on `LiveChart` or
`LiveChartSeries`. It hands you a single per-frame `scale` `SharedValue` plus pure
mapping worklets.

```ts theme={null}
interface ChartOverlayContext {
  scale: SharedValue<ChartScale>;                               // live scale, recomputed each frame
  priceToY: (price: number, scale: ChartScale) => number;       // price → canvas Y px (-1 before layout)
  yToPrice: (y: number, scale: ChartScale) => number | null;    // canvas Y px → price (clamped; null before layout)
  timeToX: (time: number, scale: ChartScale) => number;         // unix seconds → canvas X px
  xToTime: (x: number, scale: ChartScale) => number;            // canvas X px → unix seconds
}

interface ChartScale {
  min: number;        // live Y-axis lower bound (price at the plot bottom)
  max: number;        // live Y-axis upper bound (price at the plot top)
  window: number;     // visible time window in seconds
  now: number;        // right-edge timestamp (unix seconds)
  plot: ChartPlotRect;
}

interface ChartPlotRect {
  left: number;    // padding.left
  top: number;     // padding.top
  right: number;   // canvasWidth - padding.right
  bottom: number;  // canvasHeight - padding.bottom
  width: number;   // full canvas width
  height: number;  // full canvas height
}
```

**Easiest path — the `usePriceY` / `useTimeX` hooks.** They project a price / time to
a `SharedValue<number>` that tracks the live axis for you. Render one component per
level and read the value in your `useAnimatedStyle`:

```tsx theme={null}
function PriceLevel({ ctx, price }) {
  const y = usePriceY(ctx, price); // reactive — tracks the rescaling axis
  const style = useAnimatedStyle(() => ({ transform: [{ translateY: y.get() }] }));
  return <Animated.View style={style} />;
}
```

**Manual path.** Read `scale.get()` inside your worklet — that read subscribes it to
the live scale — then feed the snapshot to the pure mappings. (Reanimated only
observes SharedValues read directly in a worklet's closure, so the mappings take the
snapshot as an argument rather than reading it themselves.)

```tsx theme={null}
const style = useAnimatedStyle(() => {
  const s = scale.get();          // subscribe to the live scale
  const y = priceToY(142.5, s);   // project a price level to its pixel
  return { transform: [{ translateY: y }] };
});
```

## DegenOptions

The most-used fields (see the source for the full tuning surface):

```ts theme={null}
interface DegenOptions {
  scale?: number;               // default 1
  downMomentum?: boolean;       // also trigger on down swings; default false
  shake?: boolean;              // default true
  shakeIntensity?: number;
  shakeDurationSec?: number;    // default 0.45
  burstParticleCount?: number;  // default 20
  particleOpacity?: number;     // default 0.55
  colors?: string | string[];
  // ...plus particle slot/size/speed/jitter tuning
}
```

## Palette

`accentColor` + `theme` derive a full `LiveChartPalette`. Override any subset via the `palette`
prop. Frequently overridden keys:

```ts theme={null}
interface LiveChartPalette {
  line: string;
  fillTop: string; fillBottom: string;
  gridLine: string; gridLabel: string;
  dotUp: string; dotDown: string; dotFlat: string;
  candleUp: string; candleDown: string; wickUp: string; wickDown: string;
  dashLine: string; refLine: string; refLabel: string;
  crosshairLine: string; crosshairDim: string;
  tooltipBg: string; tooltipText: string; tooltipBorder: string;
  // ...glow, badge, and font-size keys
}
```

## Metrics

The geometry/motion analogue of `LiveChartPalette`. Override any subset via the `metrics` prop
(per-namespace shallow merge — only the keys you set are replaced). See the
[Theming guide](/guides/theming#sizing-and-motion-tokens).

```ts theme={null}
interface LiveChartMetrics {
  badge: BadgeMetrics;
  candle: CandleMetrics;
  grid: GridMetrics;
  motion: MotionMetrics;
  emptyState: EmptyStateMetrics;
}

interface BadgeMetrics {
  padX: number;        // pill horizontal padding, default 10
  padY: number;        // pill vertical padding, default 3
  tailLength: number;  // tail spike toward the dot, default 5
  marginEdge: number;  // gap from the canvas edge, default 4
  dotGap: number;      // gap between the dot and the tail tip, default 12
  tailSpread: number;  // tail curve control-point spread, default 2.5
}

interface CandleMetrics {
  minBodyPx: number;      // min body height so dojis stay visible, default 1
  maxBodyPx: number;      // max body width, default 40
  bodyWidthRatio: number; // body width as a fraction of the slot, default 0.8
  minGapPx: number;       // min gap (px) between adjacent bodies; 0 = ratio-only, default 2
  bodyRadius: number;     // body corner radius (px); 0 = sharp, default 0
  wickWidth: number;      // wick (high–low line) stroke width (px), default 1
}

interface GridMetrics {
  fadeInSpeed: number;  // per-frame alpha lerp when a line/label fades in, default 0.18
  fadeOutSpeed: number; // per-frame alpha lerp when it fades out, default 0.12
}

interface MotionMetrics {
  badgeColorSpeed: number;    // badge color transition lerp speed, default 0.08
  adaptiveSpeedBoost: number; // extra catch-up over `smoothing` when the value lags, default 0.12
}

interface EmptyStateMetrics {
  labelOpacity: number; // empty-state label opacity, default 0.35
  gapPad: number;       // half-padding around the empty text, default 20
  gapFadeWidth: number; // fade width each side of the empty-text gap, default 30
}

// `metrics` prop type — every namespace and field optional:
type LiveChartMetricsOverride = {
  badge?: Partial<BadgeMetrics>;
  candle?: Partial<CandleMetrics>;
  grid?: Partial<GridMetrics>;
  motion?: Partial<MotionMetrics>;
  emptyState?: Partial<EmptyStateMetrics>;
};
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.