I love singing hymns to praise the Lord and give glory to God. There’s something truly powerful about music that lifts the spirit and helps me feel connected to heaven.

But I found myself getting frustrated when trying to use the church's online music pages. The PDF music viewer is small, hard to read, and you constantly have to scroll to the top if you’re flipping through verses or using it on a smaller screen.

So I had an idea: what if I asked ChatGPT to help me write a Tampermonkey script to enhance it?


🙌 The Result: A Distraction-Free Hymn Reader

What started as a small experiment turned into a genuinely useful enhancement. I now have a beautiful "focus mode" button that:


Before and After Screenshots

Before

before

After

after


💬 Want the Same Thing? Here’s the Prompt I Gave ChatGPT

Paste this into ChatGPT to recreate the full script:

Create a Tampermonkey userscript for this page: https://www.churchofjesuschrist.org/media/music/songs/*

The script should:
- Add a small fixed button in the top-right corner labeled 🎵 to toggle "focus mode"
- When toggled ON, hide:
  - `platform-header`
  - `body > platform-footer:nth-child(23)`
  - Side panel with this selector:
    `main#root div.Songs__PageWrapper-sc-164xdnp-3.iiQBOL div.sc-eaUbBy.bKpAaE div.Songs__PageSplitWrapper-sc-164xdnp-1.gAzrrl div.SidePanel__LeftAndRightMargins-sc-1pqfxz7-0.iMVKQX`
- Also shrink the audio player `.Songs__StyledAudioPlayer-sc-164xdnp-4` to 0.7 scale, with `padding: 0` and `top: -23px`
- Resize the canvas elements (`canvas.react-pdf__Page__canvas`) to 70% of the window width, maintaining aspect ratio
- Store original canvas size when first toggled, and restore it when toggled off
- Add ➕ and ➖ buttons to the left of the 🎵 button (visible only in focus mode) that increase/decrease canvas width by 100px, maintaining aspect ratio
- Add a large "⬆️ Jump to Top" button fixed to bottom-right, only visible in focus mode, that scrolls to `top: 300px`

The entire script should be production-ready and wrapped in standard Tampermonkey metadata. Output the full script.

🧪 Just Want the Script? Copy & Paste This

// ==UserScript==
// @name         Music Page Focus Toggle (v1.9)
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  Toggle distractions, zoom controls, and jump button (shown only in focus mode)
// @match        https://www.churchofjesuschrist.org/media/music/songs/*
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  let isFocused = false;
  const canvasData = new Map();
  const audioSelector = '.Songs__StyledAudioPlayer-sc-164xdnp-4';
  const zoomAmount = 100;

  const toggleBtn = document.createElement('button');
  toggleBtn.textContent = '🎵';
  toggleBtn.title = 'Toggle Focus Mode';
  styleButton(toggleBtn, { right: '5px' });

  const plusBtn = document.createElement('button');
  plusBtn.textContent = '➕';
  plusBtn.title = 'Zoom In';
  styleButton(plusBtn, { right: '42px', display: 'none' });

  const minusBtn = document.createElement('button');
  minusBtn.textContent = '➖';
  minusBtn.title = 'Zoom Out';
  styleButton(minusBtn, { right: '79px', display: 'none' });

  const jumpBtn = document.createElement('button');
  jumpBtn.textContent = '⬆️ Jump to Top';
  jumpBtn.title = 'Scroll to Top + 300px';
  styleButton(jumpBtn, {
    bottom: '20px',
    top: '',
    right: '20px',
    fontSize: '24px',
    padding: '16px 24px',
    borderRadius: '8px',
    background: '#28a745',
    display: 'none'
  });

  document.body.append(toggleBtn, plusBtn, minusBtn, jumpBtn);

  toggleBtn.addEventListener('click', () => {
    isFocused = !isFocused;
    updateFocusStyles(isFocused);
    [plusBtn, minusBtn, jumpBtn].forEach(btn => (btn.style.display = isFocused ? 'inline-block' : 'none'));
  });

  plusBtn.addEventListener('click', () => adjustCanvasWidthBy(zoomAmount));
  minusBtn.addEventListener('click', () => adjustCanvasWidthBy(-zoomAmount));

  jumpBtn.addEventListener('click', () => {
    window.scrollTo({ top: 300, behavior: 'smooth' });
  });

  function styleButton(btn, overrides = {}) {
    Object.assign(btn.style, {
      position: 'fixed',
      top: '5px',
      zIndex: '10000',
      padding: '5px 8px',
      fontSize: '14px',
      background: '#007BFF',
      color: '#fff',
      border: 'none',
      borderRadius: '4px',
      cursor: 'pointer',
      boxShadow: '0 2px 5px rgba(0, 0, 0, 0.3)',
      ...overrides
    });
  }

  function updateFocusStyles(focus) {
    [
      'platform-header',
      'body > platform-footer:nth-child(23)',
      'main#root div.Songs__PageWrapper-sc-164xdnp-3.iiQBOL div.sc-eaUbBy.bKpAaE div.Songs__PageSplitWrapper-sc-164xdnp-1.gAzrrl div.SidePanel__LeftAndRightMargins-sc-1pqfxz7-0.iMVKQX'
    ].forEach(selector => {
      const el = document.querySelector(selector);
      if (el) el.style.display = focus ? 'none' : '';
    });

    if (focus) {
      resizeCanvasTo70();
      adjustAudioPlayer();
    } else {
      restoreOriginalCanvasSize();
      resetAudioPlayer();
    }
  }

  function resizeCanvasTo70() {
    document.querySelectorAll('canvas.react-pdf__Page__canvas').forEach(canvas => {
      if (!canvasData.has(canvas)) {
        const rect = canvas.getBoundingClientRect();
        canvasData.set(canvas, {
          width: rect.width,
          height: rect.height
        });
      }

      const aspect = canvas.height / canvas.width;
      const newWidth = window.innerWidth * 0.7;
      const newHeight = newWidth * aspect;

      canvas.style.width = `${newWidth}px`;
      canvas.style.height = `${newHeight}px`;
      canvas.style.display = 'block';
      canvas.style.margin = '0 auto';
    });
  }

  function restoreOriginalCanvasSize() {
    document.querySelectorAll('canvas.react-pdf__Page__canvas').forEach(canvas => {
      const original = canvasData.get(canvas);
      if (original) {
        canvas.style.width = `${original.width}px`;
        canvas.style.height = `${original.height}px`;
      } else {
        canvas.style.width = '';
        canvas.style.height = '';
      }
      canvas.style.margin = '';
    });
  }

  function adjustCanvasWidthBy(delta) {
    document.querySelectorAll('canvas.react-pdf__Page__canvas').forEach(canvas => {
      const curWidth = parseFloat(canvas.style.width || canvas.offsetWidth);
      const aspect = canvas.height / canvas.width;
      const newWidth = curWidth + delta;
      const newHeight = newWidth * aspect;
      canvas.style.width = `${newWidth}px`;
      canvas.style.height = `${newHeight}px`;
    });
  }

  function adjustAudioPlayer() {
    const el = document.querySelector(audioSelector);
    if (el) {
      el.style.transform = 'scale(0.7)';
      el.style.transformOrigin = 'top right';
      el.style.padding = '0';
      el.style.top = '-23px';
      el.style.position = 'relative';
    }
  }

  function resetAudioPlayer() {
    const el = document.querySelector(audioSelector);
    if (el) {
      el.style.transform = '';
      el.style.padding = '';
      el.style.top = '';
      el.style.position = '';
    }
  }

})();

Now I can enjoy singing praises without distractions — and I hope you can too.