Circle of Fifths

circle-of-fifthsVisualizers

A pitch-class histogram on the wheel, with a tonal-centre needle.

$ pnpm dlx shadcn@latest add @pluginui/core-circle-of-fifths
Loading interactive preview…

Install

Copies the source into your project. Anything it depends on comes with it. Run this in your React project with shadcn initialized; no registry configuration is needed.

Pulls in

control-theme
Install using the registry URL
$ pnpm dlx shadcn@latest add https://pluginui.com/r/core-circle-of-fifths.json

Usage

Connect the documented props to your application or host.

example.tsx
import { CircleOfFifths } from "@/components/ui/circle-of-fifths"
import { tonalCenter } from "maruaudio/ui/shared/tonal-center"

// Chromatic order, C..B; values are peak-normalised for you.
const weights = [1, 0, 0.55, 0, 0.8, 0.6, 0, 0.9, 0, 0.55, 0, 0.45]

<CircleOfFifths
  weights={weights}
  needle={tonalCenter(weights)}
  highlightPcs={[0, 4, 7]}
/>
About Circle of Fifths

The circle of fifths makes tonality visible. Neighbouring slots are a fifth apart, so the seven notes of a key form an unbroken arc and a modulation becomes a short slide around the rim. A chromatic keyboard scatters the same information across the octave. Each pitch class becomes a radial bar whose length reflects how often that note sounded. The optional needle points to the tonal centre, with length and opacity scaled by confidence. An ambiguous or chromatic passage therefore gets a short, faint needle instead of a decisive-looking lie. Compute the centre with tonalCenter from the tonal-center library. This component does not calculate it, allowing a precomputed or smoothed estimate to use the same wheel.

Props

PropTypeDefaultDescription
weightsnumber[]—Length-12 pitch-class weights in CHROMATIC order (0 = C … 11 = B). Values are peak-normalised internally, so units may be note counts, seconds held or velocity sums.
needle{ angleRad: number, strength: number } | nullnullThe tonal centre to point at, e.g. from tonalCenter(weights). Strength drives both length and opacity. Omit for no needle.
highlightPcsnumber[]—Pitch classes to mark on the ring, typically the chord sounding now. Values are reduced mod 12, so raw MIDI numbers work.
sizenumber240Overall square size in pixels.
showLabelsbooleantrueDraw the pitch-class names around the rim.
colorstring—Bar and needle colour. Defaults to the --uikit-accent token.

Interaction

  • Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
  • Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
  • Double-click resets to defaultValue.
  • Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
  • Proper slider and switch roles with live aria-valuetext, so a screen reader announces the formatted value rather than the raw number.
  • The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.