Lyrics Page Layout Similar to ProPresenter7 Stage Layout

Description

I would like to know if it is possible to create a layout for the Lyrics page that could look similar-ish to our Stage Display in Pro7. We have used Ableset’s Lyrics page on our stage display the past two weeks and it has been great. The extra info is not important on the layout, I’m mainly just looking for the “Next” and “Current” box where the boxes would contain all text for the “current” line and the “next” line and have the text scale up or down to fit completely inside the box. Thank you for any help provided! I am loving this tool very much!

For this to work, you’ll need to use the latest beta of AbleSet, and add the [top] [nofade] [nozoom] attributes to your lyrics track.

It will look like this:

.lyrics .line {
  height: calc(var(--height) * 0.5);
  /* remove this if you don't want the gray borders */
  outline: 1px solid gray;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.lyrics .line.next .lyrics-line p {
  opacity: 1;
  color: orange;
}

I hope this helps! Let me know what you think :slight_smile:

1 Like

Thank you for this! Personally I really like the original way that the lyrics are done in Ableset and so has all of our vocalists that have used it thus far but just wanted to have an alternative ready in case. I don’t think I’ll be able to go back running Stage Display lyrics from Pro7 after using this for a few weeks.

One thing that I have (unsuccessfully) tried to accomplish is getting the text to scale up or down to fit the container so if there is a lot of text, it scales down to fit it all and if it has a small amount of text, it will scale it up to fit. I have tried a few methods to adjust the font-size dynamically (vw, vh, rem, em, etc.), and while it works, these allows the elements to push beyond the container. I feel like it will need to be calculated using Javascript. Is this possible? If not, or if it’s too convoluted, it’s no problem.

This is a great piece of software that I have loved using and has been a game changer for us. Thank you for all of your help.

Hey @iamderkis,

This would require JS, unfortunately browsers don’t have the ability to dynamically size text to fit its container. AbleSet allows you to run custom JS, so you could try using something like textFit on lines to do this.

I hope this helps!

1 Like

@iamderkis, If you need help implementing the textFit code that @leolabs recommended, I’ll be happy to lend a hand. Fee free to let me know

1 Like

Great! I am going to try and hack it around a little just to try and get some practice since it’s been a while since I’ve done much scripting but I’m sure I’ll be taking you up on that offer!

1 Like

If you’re already familiar with JS, you shouldn’t have any problems. Happy coding!:+1:

1 Like

Quick question. Where do I add the textFit folder to, to be able to reference it in the .js file?

Sorry for the delayed response. It’s been one of those crazy Mondays! :slight_smile: I would recommend the minified version of textFit which is packed inside the github folder. You can get that code in many ways, but to keep things simple, just download the zip folder here

Next, unpack the zip folder, then copy/paste: textFit.min.js into Ableset’s custom-styles folder.

Then inside of Ableset’s script.js file, paste this code:

const textFitLoaded = function() {

    console.log("textFit loaded!");
    textFit(document.querySelectorAll('.lyrics-line span'));

}

var script = document.createElement("script");

script.setAttribute("src", '/custom-styles/textFit.min.js');
script.setAttribute("type", "text/javascript");
script.onreadystatechange = textFitLoaded;
script.onload = textFitLoaded;

document.head.appendChild(script);

I couldn’t get the textFit code to produce any results but I think it has to do with the lyrics being nested inside of each .lyrics-line. I’m headed out for an event tonight but I’ll look more into this later.

1 Like

@iamderkis The results from textFit may not be what you’re expecting but here’s some working code that will get you going. First, add this css code to your styles.css file:

  .lyrics-line,
  .lyrics-line p {
    display: block;
    width: 100%;
    height: calc(var(--height) * 0.5);
  }

Then replace the js code that I originally posted with this:

const textFitLoaded = function() {

    //give Ableset time to excecute it's code
    setTimeout( function() {

        var lyrics = document.querySelectorAll('.lyrics-line span');
        //textFit requires parent elements to have static width/height
        lyrics.forEach(function (el) {
            el.style.display = "block";
            el.style.width = el.parentElement.clientWidth + "px";
            el.style.height = el.parentElement.clientHeight + "px"
        });

        textFit( lyrics, {
            alignVert: false, // if true, textFit will align vertically using css tables
            alignHoriz: true, // if true, textFit will set text-align: center
            multiLine: true, // if true, textFit will not set white-space: no-wrap
            detectMultiLine: true, // disable to turn off automatic multi-line sensing
            minFontSize: 6,
            reProcess: true, // if true, textFit will re-process already-fit nodes. Set to 'false' for better performance
            widthOnly: true, // if true, textFit will fit text to element width, regardless of text height
            alignVertWithFlexbox: false, // if true, textFit will use flexbox for vertical alignment
        });
    }, 1000 ); 
    
}

var script = document.createElement("script");
script.setAttribute("src", '/custom-styles/textFit.min.js');
script.setAttribute("type", "text/javascript");
script.onreadystatechange = textFitLoaded;
script.onload = textFitLoaded;

document.head.appendChild(script);

Hope this helps!

Thanks for your elaborate reply @RichardB!

One thing to keep in mind is that lyrics entries can change when switching between songs. It might be a good idea to use a MutationObserver to re-run the textFit code every time the lyrics lines get replaced:

setTimeout(() => {
  const target = document.querySelector(".lyrics-page .lyrics div");

  if (!target) {
    console.log("This doesn't seem to be a lyrics page");
    return;
  }

  const callback = async (mutationList) => {
    const lyrics = document.querySelectorAll(".lyrics-line span");
    const { textFit } = await import("./textFit.js");

    lyrics.forEach((el) => {
      el.style.display = "block";
      el.style.width = el.parentElement.clientWidth + "px";
      el.style.height = el.parentElement.clientHeight + "px";
    });

    // maxFontSize can be adjusted if the font becomes too large
    textFit(lyrics, { multiLine: true, maxFontSize: 300 });
  };

  const observer = new MutationObserver(callback);
  observer.observe(target, { childList: true });
  callback();

  // Since AbleSet 2.4.0, you have access to real-time updates
  ableset.getSocket("lyrics").on("tracksUpdated", () => {
    setTimeout(callback, 1000);
  });
}, 1000);

I’m using the following styles on my end:

.lyrics .line {
  height: calc(var(--height) * 0.5);
  /* remove this if you don't want the gray borders */
  outline: 1px solid gray;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  overflow: hidden;
}

.lyrics .lyrics-line,
.lyrics .lyrics-line p {
  width: 100%;
  line-height: 1;
}

.lyrics .image-line .full img {
  height: calc(var(--height) * 0.5);
  max-height: calc(var(--height) * 0.5);
}

.lyrics .line.next .lyrics-line p {
  opacity: 1;
  color: orange;
}

The textFit.js file is slightly modified to work with the import statement. You can get its source code here: textFit.js importable module · GitHub

This could be optimized even more to account for:

  • Window resizes
  • Switching to the lyrics page from another page

I hope this helps!

Thank you @leolabs! My last post was definitely not a complete solution. I love the change to allow module imports.

@leolabs @RichardB Thank you so much for your help! Works like a charm. Just going to have to dial in the max size for the amount of lyrics used but I Believe this will work perfect for what I am needing. Thank you again! Can’t wait for these features to be added to the stable releases!

1 Like

Working great!

1 Like

I’m so glad to hear that! @leolabs is the genius and I was happy to offer my two cents.

You both have been extremely helpful. I’ve worked with Ableton for about 12 years now and this tool is a game-changer. Absolutely love it.

One (extremely small) issue with the setup is that when I make an update to the lyrics file in real time, the text does not scale up to the max size for the container. It stays very small until the page is reloaded. It might not be possible to fix and it is not a big deal at all if that is just a consequence of this setup. Again, if there is no way around that, it is no big deal at all. Just wanted to mention it. Thank you both again for all of your help.

Hey @iamderkis,

I just updated the JS and CSS code in my last post to re-fit text when lyrics change. Let me know if this works for you :slight_smile:

It works great! Occasionally, it will not update (after I make a change) but that is rare.

One issue I am getting is when using images, the pages overlap each other. I am sure this is a consequence of the unique setup of my lyrics track but wondering if there was a way to fix this.

I just updated the CSS to make images only fill the current line. Could you try adding those lines and check if that works for you?

1 Like

This worked perfectly! Thank you so much!

1 Like