Plex Now Playing Marquee Display for Multiple Players

Here’s a little Panel (Single Card) display that I made for a home theater display for Plex. It has a old school marquee vibe to it and can handle multiple players at once. For best results use a dark theme for the view (makes sure that the text is white).

Requirements:

  • Card Mod from HACS
  • Mushroom Cards from HACS
  • Auto Entities from HACS

Create a new view and select Panel layout
Add a card on the panel layout and select manual and then paste in the following code:

type: custom:auto-entities
card_mod:
  style:
    hui-grid-card$: >
      {% set active_players = states.media_player | selectattr('state', 'in',
      ['playing', 'paused']) | list | length %}


      #root {
        height: calc(100vh - 65px) !important;
        display: flex !important;
        flex-direction: column !important;
        gap: 0px !important;
        
        /* THE MARGIN NUKES */
        --grid-card-gap: 0px !important;
        --stack-card-margin: 0px !important;
        --masonry-view-card-margin: 0px !important;
      }

      #root > * {
        flex: 1 1 0 !important;
        min-height: 150px !important;
        margin: 0px !important; 
        padding: 0px !important; /* <--- NEW */
      }


      {% if active_players > 0 %}

      /* The Cinematic Title Banner */

      #root::before {
        content: "NOW PLAYING";
        flex: 0 0 auto !important; /* Stops the banner from stretching */
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 50px;
        margin-bottom: 15px;
        border-radius: 12px;
        background-color: rgba(0, 0, 0, 0.5);
        
        /* The Skewed Light Beam + Sparkles */
        background-image:
          linear-gradient(115deg, transparent 0%, rgba(255,255,255,0.4) 45%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,0.4) 55%, transparent 100%),
          radial-gradient(circle at 15px 15px, white 1px, transparent 1.5px),
          radial-gradient(circle at 50px 35px, white 2px, transparent 2.5px),
          radial-gradient(circle at 25px 45px, rgba(255,255,255,0.7) 1px, transparent 1.5px),
          radial-gradient(circle at 80px 10px, white 1.5px, transparent 2px);
        background-size: 200% 100%, 40px 40px, 70px 70px, 50px 50px, 90px 90px;
        background-repeat: no-repeat, repeat, repeat, repeat, repeat;
        
        /* Text Styling */
        font-size: 24px;
        font-weight: 900;
        letter-spacing: 6px;
        animation: root-sweep 4s infinite, root-pulse 4s infinite;
      }


      @keyframes root-sweep {
        0% { background-position: -100% 0, 0 0, 0 0, 0 0, 0 0; }
        50% { background-position: 200% 0, 0 0, 0 0, 0 0, 0 0; }
        100% { background-position: 200% 0, 0 0, 0 0, 0 0, 0 0; }
      }


      @keyframes root-pulse {
        0%, 15% { color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); }
        48%, 52% { color: #ffeb3b; text-shadow: 0 0 20px rgba(255, 235, 59, 1), 0 0 10px rgba(255, 255, 255, 0.8); }
        90%, 100% { color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); }
      }

      {% endif %}
    hui-vertical-stack-card$: >
      {% set active_players = states.media_player | selectattr('state', 'in',
      ['playing', 'paused']) | list | length %}


      #root {
        height: calc(100vh - 65px) !important;
        display: flex !important;
        flex-direction: column !important;
        gap: 0px !important; /* <--- THIS CONTROLS THE SPACE BETWEEN CARDS */
      }

      #root > * {
        flex: 1 1 0 !important;
        min-height: 150px !important;
        margin: 0 !important; /* <--- THIS DELETES HOME ASSISTANT'S DEFAULT EXTRA PADDING */
      }


      {% if active_players > 0 %}

      /* The Cinematic Title Banner */

      #root::before {
        content: "NOW PLAYING";
        flex: 0 0 auto !important; /* Stops the banner from stretching */
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 50px;
        margin-bottom: 15px;
        border-radius: 12px;
        background-color: rgba(0, 0, 0, 0.5);
        
        /* The Skewed Light Beam + Sparkles */
        background-image:
          linear-gradient(115deg, transparent 0%, rgba(255,255,255,0.4) 45%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,0.4) 55%, transparent 100%),
          radial-gradient(circle at 15px 15px, white 1px, transparent 1.5px),
          radial-gradient(circle at 50px 35px, white 2px, transparent 2.5px),
          radial-gradient(circle at 25px 45px, rgba(255,255,255,0.7) 1px, transparent 1.5px),
          radial-gradient(circle at 80px 10px, white 1.5px, transparent 2px);
        background-size: 200% 100%, 40px 40px, 70px 70px, 50px 50px, 90px 90px;
        background-repeat: no-repeat, repeat, repeat, repeat, repeat;
        
        /* Text Styling */
        font-size: 24px;
        font-weight: 900;
        letter-spacing: 6px;
        animation: root-sweep 4s infinite, root-pulse 4s infinite;
      }


      @keyframes root-sweep {
        0% { background-position: -100% 0, 0 0, 0 0, 0 0, 0 0; }
        50% { background-position: 200% 0, 0 0, 0 0, 0 0, 0 0; }
        100% { background-position: 200% 0, 0 0, 0 0, 0 0, 0 0; }
      }


      @keyframes root-pulse {
        0%, 40% { color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); }
        48%, 52% { color: #ffeb3b; text-shadow: 0 0 20px rgba(255, 235, 59, 1), 0 0 10px rgba(255, 255, 255, 0.8); }
        60%, 100% { color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); }
      }

      {% endif %}
card:
  type: grid
  columns: 1
  square: false
card_param: cards
filter:
  include:
    - domain: media_player
      state: /playing|paused/
      entity_id: "*plex*"
      options:
        type: custom:mushroom-media-player-card
        icon_type: none
        layout: vertical
        primary_info: name
        fill_container: true
        use_media_info: true
        card_mod:
          style: |
            /* 1. Force the hidden wrapper to stretch and drop margins */
            :host {
              height: 100% !important;
              width: 100% !important;
              margin: 0px !important;  /* <--- NEW */
              padding: 0px !important; /* <--- NEW */
            }

            /* 2. Force the card to fill the wrapper and drop its margins */
            ha-card {
              height: 100% !important;
              width: 100% !important;
              margin: 0 !important; /* Kills the invisible gap outside the border */
              box-sizing: border-box !important; /* Ensures the thick 12px border doesn't cause overflow */
              
              background: url('{{ state_attr(config.entity, "entity_picture") }}');
              background-size: cover;
              background-position: center;
              background-blend-mode: saturation;
              position: relative;
              display: block !important;
              --primary-text-color: white !important;
              --secondary-text-color: rgba(255, 255, 255, 0.8) !important;
              
              /* THE HOLLYWOOD MARQUEE BORDER */
              border: 12px solid #111 !important;
              outline: 6px dotted #ffcc00 !important;
              outline-offset: -16px !important;
              animation: marquee-glow 2s infinite alternate;
            }
            /* Player Name (Top Left) - Matching the white-on-black look */
            ha-card::before {
              content: "{{ state_attr(config.entity, 'friendly_name') }}";
              position: absolute;
              top: 12px;
              left: 12px;
              font-size: 14px;
              font-weight: bold;
              color: white;
              background: rgba(0,0,0,0.6);
              padding: 4px 10px;
              border-radius: 4px;
              z-index: 2;
            }
            /* Media Info Box (Top Right) */
            mushroom-state-item {
              position: absolute !important;
              top: 12px !important;
              right: 12px !important;
              bottom: auto !important; /* Stops it from stretching downward */
              height: max-content !important; /* Forces the box to shrink-wrap the text */
              background: rgba(0, 0, 0, 0.6) !important;
              padding: 4px 10px !important;
              border-radius: 4px !important;
              max-width: 60% !important;
              display: flex !important;
            }

            mushroom-state-info {
              text-align: right !important;
              display: flex !important;
              flex-direction: column !important; /* Stacks title and episode */
              justify-content: flex-start !important; /* Pushes text to the top */
              align-items: flex-end !important; /* Aligns text to the right edge */
              margin: 0 !important;
            }
            /* The Glowing Light Animation */
            @keyframes marquee-glow {
              0% { 
                /* Dark room corner shadow + Dim orange halo */
                box-shadow: inset 0 0 50px rgba(0,0,0,0.9), inset 0 0 10px 4px rgba(255, 150, 0, 0.1); 
                outline-color: #cc8800; /* Dimmed orange bulb */
              }
              100% { 
                /* Dark room corner shadow + BRIGHT yellow halo */
                box-shadow: inset 0 0 50px rgba(0,0,0,0.9), inset 0 0 30px 12px rgba(255, 230, 0, 0.8); 
                outline-color: #ffee00; /* Blazing yellow bulb */
              }
            }
  card_mod: null
  style: |
    /* This targets the grid container itself */
    .card-content {
      display: grid !important;
      /* This says: fill the space with cards at least 400px wide. 
         If only 1 card exists, it will take the full width! */
      grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)) !important;
      gap: 16px !important;
    }
grid_options:
  columns: 12
  rows: 1

** I tried a bunch of stuff to get rid of the margins around each mushroom media player card but couldn’t figure it out. If anyone has any better ideas let me know!