mcpField
B
bklit-studio-chart-performance

bklit-studio-chart-performance

github.com/bklitDevelopment1.8k672 installsUpdated today
Repository

About bklit-studio-chart-performance

A chart performance skill for bklit-ui contributors troubleshooting sluggish charts in Studio. It covers render isolation, static SVG paths, context separation, and validation steps.

Key features

  1. 01Tracing interaction-triggered re-renders
  2. 02Separating stable data from hover state
  3. 03Using static paths after enter animation
  4. 04Memoizing chart context and preview data
  5. 05Studio performance validation checklist

Use cases

  1. 01Investigating lag during slider interaction
  2. 02Reducing repeated work on legend hover
  3. 03Optimizing rendering during canvas pan
  4. 04Checking chart interactions before release

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/bklit/bklit-ui --skill bklit-studio-chart-performance

After installing, type/bklit-studio-chart-performancein Claude Code to confirm it loaded.

Details

From the project README

Studio chart performance

Use when a chart feels sluggish in Studio but similar charts (e.g. pie-chart) are fine.

One-line rule

Keep enter animation on paths if you need it, then drop Motion path subscriptions and isolate hover so Studio slider and legend updates don't replay expensive arc/path math across every series every frame.


1. Find what re-renders on every interaction

Studio updates displayState on every slider tick and on legend/slice hover. Trace:

  • Does hover live in the same context as data, scales, and animation config?
  • Does the preview recreate children (data.map, pattern defs, motion props) every render?
  • Does the chart remount unnecessarily (key tied to motion signature vs manual replay)?

Pattern: Split context like cartesian / pie charts — stable slice (data, geometry, animation config) vs hover slice (hoveredIndex, tooltip). Consumers that don't need hover use only the stable hook (usePieStable, useRingStable, useChartStable, …).

Studio pan: Wrap chart render in StudioChartRender (packages/studio/src/components/studio-chart-render.tsx) so camera pan / FPS counter parent updates skip the chart tree when render props are unchanged.


2. Treat SVG path d animation as expensive

Animating d with Motion / useTransform + d3 arc (or similar) runs layout + paint every frame, per series.

PreferAvoid
transform / opacity for hover (compositor-friendly)Continuous d morphing after enter is done
Static d once enter finishesKeeping Motion subscriptions on d for the chart's lifetime
Enter animation only, then static pathsRe-running enter path math on unrelated prop changes

Pattern: useMountProgress for enter → when progress ≥ 1 (useEnterComplete), render static paths and only animate hover with x/y/opacity/scale on a motion.g wrapper (not per-path scale on motion.path).

Shared hook: packages/ui/src/charts/use-enter-complete.ts


3. Memoize chart shell context

Unmemoized provider values force all children to reconcile on every parent render.

  • Memoize the stable context object with explicit deps (data, arcs/radii, dimensions, callbacks).
  • Memoize hover context on hoveredIndex + stable setHoveredIndex (useCallback in chart shell).
  • Match isLoaded to ring/cartesian: useEffect + timeout, not a lazy useState initializer.

Reference: pie-context.tsx, ring-context.tsx, chart-context.tsx, PieChartCore / RingChartCore useMemo on provider value.


4. Studio preview–specific wins

Chart-agnostic; apply in packages/studio/src/components/charts/*-studio*.tsx:

WinHow
Conditional defsOnly pass patternDefs / gradients when a series uses patterns
Memo derived dataColored/mapped data arrays; slice/series lists (useMemo, deps: dataSeed + design fields that affect color)
Memo motion enterDon't call getStudioMotionEnterProps inline; useMemo with motion-only deps (not full state)
Memo legend hover{ hoveredIndex, setHoveredIndex } in useMemo — already in studio-legend-hover.tsx
Memo chart bodymemo() wrapper; pass primitives (chartKey, chartSize, data) not whole ctx so pan/shell re-renders skip rebuild
Disable glow in StudioshowGlow={false} on series components

Reference: pie-studio-preview.tsx, ring-studio-preview.tsx


5. Compare against a “fast” sibling in Studio

Diff the slow chart against one that feels smooth in the same editor (usually pie-chart):

CheckSlow chart often hasFast chart often has
ShellInline render, extra defsStudioChartShell + conditional patterns
Series countMany animated pathsFewer paths or simpler geometry
HoverContext + full tree re-renderStable subscribers; hover on motion.g / translate
EnterPath d wipe per seriesStatic d after enter; transform-only hover
PanChart tree rebuilds every frameStudioChartRender memo boundary

6. Validation bar

Before opening a PR:

pnpm lint
pnpm --filter @bklitui/ui check-types
pnpm --filter @bklitui/studio check-types
# scoped production build when touching studio/web

Manual /studio?chart=<slug>:

  • Enter animation
  • Hover / legend sync
  • Drag geometry sliders (no unnecessary remount)
  • Canvas pan (space + drag) after enter — FPS near pie-chart baseline
  • Pattern/gradient mode if supported

Chart status (bklit-ui)

ChartSlugStatus
Piepie-chart✅ Reference (#120)
Ringring-chart✅ Aligned to checklist (context split, static paths, StudioChartRender, preview memo)
Radar / Funnel / ChoroplethvariousPartial — run checklist
Cartesian / scatter / live-linevarious✅ #91 decimation + hover batching
Sankeysankey-chartuseTransform on link stroke — candidate for useEnterComplete
Gaugegauge-chartLow priority (single arc)

Key files

AreaPath
Enter-complete hookpackages/ui/src/charts/use-enter-complete.ts
Pie referencepackages/ui/src/charts/pie-slice.tsx, pie-context.tsx, pie-studio-preview.tsx
Ringpackages/ui/src/charts/ring.tsx, ring-chart.tsx, ring-studio-preview.tsx
Pan isolationpackages/studio/src/components/studio-chart-render.tsx
Registrypackages/studio/src/lib/registry.tsx

Comments

Markdown supported