Coordinate System: Beats Are the Domain

SkillMedia

An open ecosystem for music production.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Coordinate System: Beats Are the Domain skill

What this skill tells your AI

The instructions your AI receives, as published by conceptual-machines/magda-core in .claude/skills/coordinate-system/SKILL.md and read by ahel’s review.

Rule

MAGDA's UI domain is beats, not seconds. The zoom unit is pixels per beat (ppb). All UI coordinate math (pixel positioning, grid drawing, clip bounds, selections) must work in beats natively.

Seconds are only used at the boundary — when talking to the audio engine, file I/O, or external APIs. Never convert seconds→beats→pixels when a beat value is already available.

Why

Converting seconds→beats introduces floating point drift: startTime * BPM / 60.0 does not always equal startBeats exactly. When this drifted value is multiplied by zoom and truncated to int, the pixel position shifts differently at different zoom levels. This causes clips to visually appear at different ruler positions depending on zoom — a recurring bug that has been fixed multiple times.

How to Apply

Clip positioning

Always use startBeats / lengthBeats for pixel calculations. Fall back to seconds conversion only if beat values are not set (< 0):

double beats = (clip->startBeats >= 0.0) ? clip->startBeats : clip->startTime * BPM / 60.0;
int pixelX = beatsToPixel(beats);

Pixel conversion functions

  • beatsToPixel(double beats) / pixelToBeats(int pixel) — primary, no conversion
  • timeToPixel(double seconds) / pixelToTime(int pixel) — convenience wrappers that convert through beats

State values

Many state values (editCursorPosition, selection times, etc.) are stored in seconds for historical reasons. When converting these to pixels, use timeToPixel() which goes through beats internally. But when beat-domain equivalents exist (e.g., startBeats, lengthBeats, selection.startBeats), prefer those.

New code

When adding new UI positioning code, always ask: "do I have this value in beats already?" If yes, use beatsToPixel() directly. Never compute seconds * BPM / 60 when a beat value is sitting right there.

Signals

GitHub stars
206
Forks
24
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
coordinate-system
Source
github.com/conceptual-machines/magda-core