Hermes Agent commited on
Commit
bfa9bd9
·
1 Parent(s): 8300a1e

feat: sync full-screen ambient blurred backdrop with spotlight hero theme colors

Browse files
apex/ui/abyss.css CHANGED
@@ -5647,3 +5647,75 @@ div[data-category="cast"] .cardScalable,
5647
  box-sizing: border-box !important;
5648
  }
5649
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5647
  box-sizing: border-box !important;
5648
  }
5649
  }
5650
+
5651
+ /* ========================================================
5652
+ APEX DYNAMIC AMBIENT BACKDROP SYNCHRONIZATION
5653
+ Full-screen dynamic blur synced with active Spotlight item
5654
+ ======================================================== */
5655
+ #abyss-spotlight-backdrop {
5656
+ position: fixed;
5657
+ inset: 0;
5658
+ width: 100vw;
5659
+ height: 100vh;
5660
+ pointer-events: none;
5661
+ z-index: 0;
5662
+ overflow: hidden;
5663
+ opacity: 0;
5664
+ transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1);
5665
+ background-color: #050508;
5666
+ }
5667
+
5668
+ html.abyss-spotlight-visible #abyss-spotlight-backdrop {
5669
+ opacity: 1;
5670
+ }
5671
+
5672
+ .abyss-spotlight-backdrop-layer {
5673
+ position: absolute;
5674
+ inset: -50px;
5675
+ background-size: cover;
5676
+ background-position: center top;
5677
+ opacity: 0;
5678
+ filter: blur(58px) saturate(165%) contrast(115%) brightness(40%);
5679
+ transform: scale(1.15);
5680
+ transition: opacity 1.1s cubic-bezier(0.16, 1, 0.3, 1), transform 1.5s cubic-bezier(0.16, 1, 0.3, 1);
5681
+ will-change: opacity, transform;
5682
+ }
5683
+
5684
+ .abyss-spotlight-backdrop-layer.is-active {
5685
+ opacity: 1;
5686
+ transform: scale(1.03);
5687
+ }
5688
+
5689
+ /* Atmospheric contrast gradient: transparent at top, soft vignette downwards, anchoring into true black */
5690
+ #abyss-spotlight-backdrop::after {
5691
+ content: "";
5692
+ position: absolute;
5693
+ inset: 0;
5694
+ background: linear-gradient(
5695
+ to bottom,
5696
+ rgba(5, 5, 8, 0.15) 0%,
5697
+ rgba(5, 5, 8, 0.35) 25%,
5698
+ rgba(5, 5, 8, 0.65) 55%,
5699
+ rgba(5, 5, 8, 0.88) 80%,
5700
+ #050508 100%
5701
+ );
5702
+ pointer-events: none;
5703
+ }
5704
+
5705
+ /* Ensure background transparency pass-through on the home screen when spotlight is active */
5706
+ html.abyss-spotlight-visible body,
5707
+ html.abyss-spotlight-visible .backgroundContainer,
5708
+ html.abyss-spotlight-visible #indexPage,
5709
+ html.abyss-spotlight-visible .pageTabContent,
5710
+ html.abyss-spotlight-visible .homeSectionsContainer,
5711
+ html.abyss-spotlight-visible .mainAnimatedPages,
5712
+ html.abyss-spotlight-visible .pageContainer {
5713
+ background-color: transparent !important;
5714
+ background: transparent !important;
5715
+ }
5716
+
5717
+ html.abyss-spotlight-visible #indexPage,
5718
+ html.abyss-spotlight-visible .homeSectionsContainer {
5719
+ position: relative;
5720
+ z-index: 1;
5721
+ }
apex/ui/spotlight-loader.js CHANGED
@@ -24,6 +24,7 @@
24
  var backdropLayerA = null;
25
  var backdropLayerB = null;
26
  var activeBackdropLayer = null;
 
27
 
28
  function safe(fn) {
29
  // Runs fn and swallows/reports any error so one failure never kills the loader.
@@ -55,6 +56,16 @@
55
 
56
  function clearSpotlightBackdrop() {
57
  safe(function () {
 
 
 
 
 
 
 
 
 
 
58
  var els = document.querySelectorAll(BACKDROP_SELECTOR + "[" + BACKDROP_MARK_ATTR + "]");
59
  for (var i = 0; i < els.length; i++) {
60
  els[i].style.backgroundImage = "";
@@ -95,34 +106,37 @@
95
  }
96
 
97
  function installBackdropOverlay() {
98
- if (backdropOverlay) return;
99
- var container = document.querySelector(".backdropContainer");
100
- if (!container || !container.parentNode) return;
101
-
102
- backdropOverlay = document.createElement("div");
103
- backdropOverlay.id = "abyss-spotlight-backdrop";
104
- backdropLayerA = document.createElement("div");
105
- backdropLayerB = document.createElement("div");
106
- backdropLayerA.className = "abyss-spotlight-backdrop-layer";
107
- backdropLayerB.className = "abyss-spotlight-backdrop-layer";
108
- backdropOverlay.appendChild(backdropLayerA);
109
- backdropOverlay.appendChild(backdropLayerB);
110
 
111
- container.parentNode.insertBefore(backdropOverlay, container.nextSibling);
 
 
 
 
 
 
 
 
 
112
 
113
- var style = document.createElement("style");
114
- style.id = "abyss-spotlight-backdrop-style";
115
- style.textContent =
116
- "#abyss-spotlight-backdrop{position:fixed;inset:0;pointer-events:none;opacity:0;transition:opacity .6s ease;}" +
117
- "html.abyss-spotlight-visible #abyss-spotlight-backdrop{opacity:1;}" +
118
- ".abyss-spotlight-backdrop-layer{position:absolute;inset:0;background-size:cover;background-position:center;opacity:0;" +
119
- "transition:opacity .9s ease;filter:blur(var(--abyss-backdrop-blur,23px)) saturate(120%) contrast(120%) brightness(25%);}" +
120
- ".abyss-spotlight-backdrop-layer.is-active{opacity:1;}";
121
- document.head.appendChild(style);
122
  }
123
 
124
  function setSpotlightBackdrop(url) {
125
- if (!url || !backdropOverlay) return;
 
 
 
126
  safe(function () {
127
  var incoming = activeBackdropLayer === backdropLayerA ? backdropLayerB : backdropLayerA;
128
  var outgoing = activeBackdropLayer;
@@ -136,7 +150,7 @@
136
  if (outgoing && outgoing !== incoming) {
137
  setTimeout(function () {
138
  outgoing.classList.remove("is-active");
139
- }, 50);
140
  }
141
  });
142
  activeBackdropLayer = incoming;
@@ -244,7 +258,6 @@
244
  }
245
 
246
  window.addEventListener("message", function (event) {
247
- if (!currentIframe || event.source !== currentIframe.contentWindow) return;
248
  if (!event.data || event.data.type !== "abyss-spotlight") return;
249
  if (event.data.action === "leave") {
250
  spotlightFocused = false;
@@ -292,7 +305,11 @@
292
  if (action !== lastAction) {
293
  postToFrame(iframe, action);
294
  lastAction = action;
295
- if (action === "pause") clearSpotlightBackdrop();
 
 
 
 
296
  }
297
  });
298
  };
 
24
  var backdropLayerA = null;
25
  var backdropLayerB = null;
26
  var activeBackdropLayer = null;
27
+ var currentBackdropUrl = null;
28
 
29
  function safe(fn) {
30
  // Runs fn and swallows/reports any error so one failure never kills the loader.
 
56
 
57
  function clearSpotlightBackdrop() {
58
  safe(function () {
59
+ currentBackdropUrl = null;
60
+ if (backdropLayerA) {
61
+ backdropLayerA.classList.remove("is-active");
62
+ backdropLayerA.style.backgroundImage = "";
63
+ }
64
+ if (backdropLayerB) {
65
+ backdropLayerB.classList.remove("is-active");
66
+ backdropLayerB.style.backgroundImage = "";
67
+ }
68
+ activeBackdropLayer = null;
69
  var els = document.querySelectorAll(BACKDROP_SELECTOR + "[" + BACKDROP_MARK_ATTR + "]");
70
  for (var i = 0; i < els.length; i++) {
71
  els[i].style.backgroundImage = "";
 
106
  }
107
 
108
  function installBackdropOverlay() {
109
+ if (backdropOverlay && backdropOverlay.isConnected) return;
110
+ var container = document.querySelector(".backgroundContainer") || document.querySelector(".backdropContainer") || document.body;
111
+ if (!container) return;
 
 
 
 
 
 
 
 
 
112
 
113
+ if (!backdropOverlay) {
114
+ backdropOverlay = document.createElement("div");
115
+ backdropOverlay.id = "abyss-spotlight-backdrop";
116
+ backdropLayerA = document.createElement("div");
117
+ backdropLayerB = document.createElement("div");
118
+ backdropLayerA.className = "abyss-spotlight-backdrop-layer";
119
+ backdropLayerB.className = "abyss-spotlight-backdrop-layer";
120
+ backdropOverlay.appendChild(backdropLayerA);
121
+ backdropOverlay.appendChild(backdropLayerB);
122
+ }
123
 
124
+ if (!backdropOverlay.isConnected) {
125
+ if (container === document.body) {
126
+ document.body.insertBefore(backdropOverlay, document.body.firstChild);
127
+ } else if (container.parentNode) {
128
+ container.parentNode.insertBefore(backdropOverlay, container.nextSibling);
129
+ } else {
130
+ document.body.appendChild(backdropOverlay);
131
+ }
132
+ }
133
  }
134
 
135
  function setSpotlightBackdrop(url) {
136
+ if (!url) return;
137
+ currentBackdropUrl = url;
138
+ installBackdropOverlay();
139
+ if (!backdropOverlay) return;
140
  safe(function () {
141
  var incoming = activeBackdropLayer === backdropLayerA ? backdropLayerB : backdropLayerA;
142
  var outgoing = activeBackdropLayer;
 
150
  if (outgoing && outgoing !== incoming) {
151
  setTimeout(function () {
152
  outgoing.classList.remove("is-active");
153
+ }, 450);
154
  }
155
  });
156
  activeBackdropLayer = incoming;
 
258
  }
259
 
260
  window.addEventListener("message", function (event) {
 
261
  if (!event.data || event.data.type !== "abyss-spotlight") return;
262
  if (event.data.action === "leave") {
263
  spotlightFocused = false;
 
305
  if (action !== lastAction) {
306
  postToFrame(iframe, action);
307
  lastAction = action;
308
+ if (action === "pause") {
309
+ clearSpotlightBackdrop();
310
+ } else if (action === "resume" && currentBackdropUrl) {
311
+ setSpotlightBackdrop(currentBackdropUrl);
312
+ }
313
  }
314
  });
315
  };
apex/ui/spotlight.css CHANGED
@@ -52,10 +52,10 @@ body {
52
  position: absolute;
53
  inset: 0;
54
  background:
55
- /* Seamless bottom fade directly to OLED pitch black #000000 */
56
- linear-gradient(to top, #000000 0%, rgba(0, 0, 0, 0.88) 22%, rgba(0, 0, 0, 0.45) 48%, transparent 80%),
57
  /* Left side reading gradient ensuring text/metadata has 100% contrast */
58
- linear-gradient(to right, #000000 0%, rgba(0, 0, 0, 0.8) 32%, rgba(0, 0, 0, 0.35) 58%, transparent 85%);
59
  pointer-events: none;
60
  }
61
 
 
52
  position: absolute;
53
  inset: 0;
54
  background:
55
+ /* Seamless bottom fade that allows ambient colors to radiate down through content rails */
56
+ linear-gradient(to top, rgba(5, 5, 8, 0.82) 0%, rgba(5, 5, 8, 0.55) 25%, rgba(0, 0, 0, 0.22) 55%, transparent 82%),
57
  /* Left side reading gradient ensuring text/metadata has 100% contrast */
58
+ linear-gradient(to right, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.78) 32%, rgba(0, 0, 0, 0.35) 58%, transparent 85%);
59
  pointer-events: none;
60
  }
61
 
apex/ui/spotlight.html CHANGED
@@ -810,11 +810,10 @@
810
  }
811
 
812
  try {
813
- const syncUrl = artwork.backdrop
814
- ? (artwork.primaryBackdrop ? itemImageUrls(item).primary : (artwork.usedThumb ? itemImageUrls(item).thumb : itemImageUrls(item).backdrop))
815
- : null;
816
  if (syncUrl) {
817
- window.parent.postMessage({ type: 'abyss-spotlight', action: 'backdrop-sync', url: syncUrl }, window.location.origin);
 
818
  }
819
  } catch { /* parent sync is optional */ }
820
  let episodePrefix = '';
 
810
  }
811
 
812
  try {
813
+ const syncUrl = artwork.backdrop || (artwork.primaryBackdrop ? itemImageUrls(item).primary : (artwork.usedThumb ? itemImageUrls(item).thumb : itemImageUrls(item).backdrop));
 
 
814
  if (syncUrl) {
815
+ const origin = (window.location && window.location.origin && window.location.origin !== 'null') ? window.location.origin : '*';
816
+ window.parent.postMessage({ type: 'abyss-spotlight', action: 'backdrop-sync', url: syncUrl }, origin);
817
  }
818
  } catch { /* parent sync is optional */ }
819
  let episodePrefix = '';