braccato 0.0.0

braccato makes it dead simple to show synced lyrics.

The lyrics renderer from Better Lyrics, one of the most used YouTube Music extensions, as a single custom element with no dependencies.

Package manager

Each syllable lights up as it is sung.

Import the element and its three stylesheets, point it at an audio or video element, and give it an array of lines. It follows that element's playback, and clicking a line seeks to it.

Autoscroll moves the nearest scrollable parent. To use a different one, set view.host = { getScrollElement: () => frame }, like this page does.

Pick a song

Or play your own

Or drop an audio file anywhere on this page.

Line synced, or not synced at all.

There is no mode to set. Leave out parts and whole lines light up. Leave out the times too and you get plain, unsynced lyrics.

How the built-in lyrics are timed

Two voices, and the one behind them.

Give a line an agent and the second singer's lines move to the other side. Background vocals show up smaller, under their line.

Translations stream in

These often arrive after the lyrics. Add them to a line at any time and they animate in. Changing the song or timing clears them.

Credits close the song

Pass songwriters and the last line hands over to who wrote it. The credits wait, dim, and brighten once the song ends. One CSS rule hides them.

One line at a time, over the picture.

Set layout="stage" and load stage.css, and the element shows only the lines being sung, like subtitles over a video. It fills the nearest positioned parent. The theme stays the same.

Layout

A backdrop that follows the words

braccato:stage-layout gives the box around the sung lines, or null when nobody is singing. This page draws the plate behind them from it, outside the element, so no theme can restyle it.

Duets keep their sides

Each singer stays on their own side of the stage. Everyone together stays in the middle.

A stage places lines by their time, so unsynced lyrics show nothing. The element says so: status becomes "unsynced-on-stage" and it dispatches braccato:error with phase: "layout".

A theme is a stylesheet.

Style the class names with plain CSS. Settings, like where the active line sits, go in blyrics-* comments in the same stylesheet, so there is no separate config. An empty theme resets everything.

Pick a starting point

Edit it live

All theme settings

Bring your own lyrics.

The element only takes an array. @braccato/parsers reads a lyrics file, detects the format, and gives you that array.

  • TTML
  • LRC
  • SRT
  • QRC
  • Plain text

Read the parsers guide
Show the array the element got

            

Shift the timing, scroll the lyrics.

Both apply straight away, playing or paused. The offset goes through tickOptions.

0 ms

Moves the lyrics against the audio. Negative values make the words show up earlier.

The full API.

Twelve properties, five attributes, five events, and the class names themes can use. The renderer guide covers each one in more depth.

Reference section

Properties

You can set any of these before the element is in the document. They are all applied when it connects.

Read the renderer guide

Light DOM, so your CSS reaches it.

The element renders into its own children, not a shadow root, so your page's CSS reaches the lines and the package's @property registrations work. This page checks both when it loads.

HTML written before the script loads still works

The tag is in the HTML before the script defines it. Once the script loads, its source and theme attributes should still apply. Checked once, on load.

Checking once the script loads.

Your CSS reaches the lines

This page's CSS tightens the letter spacing on the container. It couldn't with a shadow root.

Events

Every braccato:* event, newest first.

    One view per document

    Two views on one page share the theme <style>, scroll padding, settings and playback clock, so the second overrides the first. That is fine if both use the same theme. If the themes differ, both dispatch braccato:error with phase: "conflict", their status becomes "theme-conflict", and both keep rendering.