diff --git a/now-playing/settings/settings.json b/now-playing/settings/settings.json
index c68c7a3..f2a1259 100644
--- a/now-playing/settings/settings.json
+++ b/now-playing/settings/settings.json
@@ -45,6 +45,10 @@
{
"value": "vinyl",
"label": "Vinyl"
+ },
+ {
+ "value": "color-palette",
+ "label": "Color Palette"
}
],
"defaultValue": "standard",
diff --git a/now-playing/themes/color-palette/index.html b/now-playing/themes/color-palette/index.html
new file mode 100644
index 0000000..c5e07ba
--- /dev/null
+++ b/now-playing/themes/color-palette/index.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/now-playing/themes/color-palette/script.js b/now-playing/themes/color-palette/script.js
new file mode 100644
index 0000000..bffb9b2
--- /dev/null
+++ b/now-playing/themes/color-palette/script.js
@@ -0,0 +1,125 @@
+///////////////////
+// PAGE ELEMENTS //
+///////////////////
+
+const mainWrapper = document.getElementById('main-wrapper');
+// Color Boxes
+const boxVibrant = document.getElementById('box-vibrant');
+const boxMuted = document.getElementById('box-muted');
+const boxDarkVibrant = document.getElementById('box-dark-vibrant');
+const boxDarkMuted = document.getElementById('box-dark-muted');
+const boxLightVibrant = document.getElementById('box-light-vibrant');
+const boxLightMuted = document.getElementById('box-light-muted');
+
+// Primary Text Labels (for Hex codes)
+const labelVibrant = document.getElementById('label-vibrant');
+const labelMuted = document.getElementById('label-muted');
+const labelDarkVibrant = document.getElementById('label-dark-vibrant');
+const labelDarkMuted = document.getElementById('label-dark-muted');
+const labelLightVibrant = document.getElementById('label-light-vibrant');
+const labelLightMuted = document.getElementById('label-light-muted');
+
+
+
+/////////////////
+// GLOBAL VARS //
+/////////////////
+
+const colorRoles = ['Vibrant', 'Muted', 'DarkVibrant', 'DarkMuted', 'LightVibrant', 'LightMuted'];
+
+
+
+////////////////
+// PAGE SETUP //
+////////////////
+
+// Set container width
+if (maxWidth > 0)
+ mainWrapper.style.width = `${maxWidth}px`;
+else
+ mainWrapper.style.width = `100%`;
+
+// Set primary and secondary text visibility
+if (showPrimary)
+ document.documentElement.style.setProperty('--show-primary', '');
+else
+ document.documentElement.style.setProperty('--show-primary', 'none');
+
+if (showSecondary)
+ document.documentElement.style.setProperty('--show-secondary', '');
+else
+ document.documentElement.style.setProperty('--show-secondary', 'none');
+
+
+
+////////////////////
+// CORE FUNCTIONS //
+////////////////////
+
+async function ChangeTrack(mediaProps, accentColorPalette) {
+ // Map elements for easy lookup
+ const labels = {
+ Vibrant: labelVibrant,
+ Muted: labelMuted,
+ DarkVibrant: labelDarkVibrant,
+ DarkMuted: labelDarkMuted,
+ LightVibrant: labelLightVibrant,
+ LightMuted: labelLightMuted
+ };
+
+ const boxes = {
+ Vibrant: boxVibrant,
+ Muted: boxMuted,
+ DarkVibrant: boxDarkVibrant,
+ DarkMuted: boxDarkMuted,
+ LightVibrant: boxLightVibrant,
+ LightMuted: boxLightMuted
+ };
+
+ // Fade out all labels
+ colorRoles.forEach(role => {
+ labels[role].style.opacity = 0;
+ });
+
+ // Wait for fade, then swap text, colors, and restore opacity
+ setTimeout(() => {
+ colorRoles.forEach(role => {
+ const colorValue = accentColorPalette[role];
+
+ labels[role].textContent = colorValue;
+ boxes[role].style.setProperty('--box-bg', colorValue);
+ boxes[role].style.color = colorValue;
+ labels[role].style.opacity = '';
+ });
+ }, 250);
+}
+
+function SetProgressInfo(timelineProps, currentPositionMs, accentColorPalette) {
+ const durationMs = timelineProps.EndTime;
+
+ let progressPercent = durationMs > 0 ? (currentPositionMs / durationMs) * 100 : 0;
+ progressPercent = Math.min(100, Math.max(0, progressPercent));
+
+ if (durationMs <= 0 || !showProgressBar)
+ progressPercent = 100;
+
+ const clipRight = 100 - progressPercent;
+
+ const boxes = {
+ Vibrant: boxVibrant,
+ Muted: boxMuted,
+ DarkVibrant: boxDarkVibrant,
+ DarkMuted: boxDarkMuted,
+ LightVibrant: boxLightVibrant,
+ LightMuted: boxLightMuted
+ };
+
+ // Update variables for each box dynamically via loop
+ colorRoles.forEach(role => {
+ const box = boxes[role];
+ if (box && accentColorPalette[role]) {
+ box.style.setProperty('--box-bg', accentColorPalette[role]);
+ box.style.setProperty('--clip-right', `${clipRight}%`);
+ }
+ });
+}
\ No newline at end of file
diff --git a/now-playing/themes/color-palette/style.css b/now-playing/themes/color-palette/style.css
new file mode 100644
index 0000000..e4a3090
--- /dev/null
+++ b/now-playing/themes/color-palette/style.css
@@ -0,0 +1,64 @@
+:root {
+ --border-radius: 10px;
+}
+
+#main-wrapper {
+ width: 500px;
+ opacity: 0;
+}
+
+#color-palette {
+ display: flex;
+ gap: 0.5em;
+ flex-direction: column;
+ width: 100%;
+}
+
+.color-box {
+ display: flex;
+ align-items: flex-end;
+ padding: 0.5em;
+ border-radius: var(--border-radius);
+ text-align: var(--text-alignment);
+ height: 5em;
+ position: relative;
+ overflow: hidden;
+}
+
+.color-box::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: var(--box-bg);
+ clip-path: inset(0 var(--clip-right, 0%) 0 0);
+ z-index: 1;
+ transition: all 1s ease;
+}
+
+.color-box .color-info {
+ position: relative;
+ z-index: 2;
+}
+
+.color-info {
+ text-transform: uppercase;
+ opacity: 0.5;
+ width: 100%;
+ mix-blend-mode: difference;
+ display: flex;
+ flex-direction: column;
+}
+
+.primary-text {
+ font-size: 1em;
+ font-weight: 700;
+ transition: opacity 0.5s ease;
+ display: var(--show-primary);
+}
+
+.secondary-text {
+ opacity: 0.7;
+ font-size: 0.7em;
+ font-weight: 700;
+ display: var(--show-secondary);
+}
\ No newline at end of file