Drum Lane

drum-laneViewers

Named lanes and hits drawn where they land, so swing is visible.

$ pnpm dlx shadcn@latest add @pluginui/core-drum-lane
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

piano-roll-geometrycontrol-theme
Install using the registry URL
$ pnpm dlx shadcn@latest add https://pluginui.com/r/core-drum-lane.json

Usage

Connect the documented props to your application or host.

example.tsx
import { DrumLane } from "@/components/ui/drum-lane"

const lanes = [
  { id: "kick", label: "Kick" },
  { id: "snare", label: "Snare" },
  { id: "hat", label: "Hat" },
]

// The host owns the clock: playhead is a beat position, null hides the cursor.
<DrumLane
  lanes={lanes}
  hits={hits}              // { id, lane, startBeats, durationBeats?, velocity?, accent? }
  bars={2}
  playhead={playing ? loopBeats : null}
  onHitActivate={(hit) => audition(hit.lane)}
/>
About Drum Lane

The rhythm sibling of the piano roll. Named lanes such as Kick, Snare and Hat run down the left, with a beat grid across. Each hit appears as a bright dot at its exact onset, so pushed or swung hits sit off the gridline instead of snapping to a step's middle. The step-dot preview it replaces quantised the picture, making straight and swung sixteenths look identical. Here the sixteenth grid stays legible while each marker shows the hit's actual position. Marker size and opacity show velocity; ghost notes look faint, accents get a ring, and sustained hits such as an open hat or ride grow a tail. The component reuses the piano roll's machinery through the shared geometry core: the same beat axis, host-driven playhead that disappears when transport stops, active-hit highlight, and --uikit-* theming that follows a host repainting per mode. Drum-specific changes are taller rows, clipped text labels instead of a keyboard, and hits placed by lane rather than pitch.

Props

PropTypeDefaultDescription
lanesDrumLaneRow[]—The lanes top to bottom, each with a stable id (hits reference it), a label for the gutter, and an optional per-lane color.
hitsDrumHit[]—Each hit is placed by lane and startBeats, never by pitch. It may also include durationBeats (a tail; 0 is a pure onset), velocity (0..127, drawn as marker size and opacity), and an accent flag that adds a ring. Hits whose lane matches no row are dropped.
bars / beatsPerBarnumber—The pattern's length in bars, and the beats a bar counts (default 4).
playheadnumber | null—Absolute beat the host's clock is on. Drawn as a lit head with a bar.beat.sixteenth readout; null draws no cursor, so a stopped transport shows nothing pinned at zero.
highlightActiveHitsbooleantrueLight up the hit the playhead is on, for live feedback on what is sounding. No effect while the playhead is null.
subdivisionsnumber4Grid lines per beat. 4 draws the sixteenth grid, which is what makes an off-grid (swung, pushed) hit read as off-grid. Bar and beat lines are always drawn and heaviest.
onSelectionChange / selectedIds(ids) => void / string[]—Selection. Present makes hits selectable (click to select, Shift-click to extend); absent is read-only.
onHitActivate(hit: DrumHit) => void—Fires on a plain click or Enter/Space on a hit. Use it to audition the hit.
scheme"inherit" | "light" | "dark""inherit"Colour scheme, scoped to the component so a light lane can sit inside a dark module. The accent is left to inherit so the host's team colour lights the hits.
rowHeightnumber30Row height in pixels. Drum rows are intentionally tall to make hits easy to read.
gutterWidthnumber60Width of the lane-label gutter, in layout px.
colorstring—Override the accent for this instance. Otherwise the lane reads --uikit-accent, so it follows a themed host automatically.

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.