[object Object]

← back to Designer Wallcoverings

Fix collection rotating-hero hydration race: re-home rotator into Boost header

c9b7c05eb87aaa37a069c70e31e539a394fb8cc3 · 2026-06-23 16:27:38 -0700 · Steve

Root cause: dw-hero-rotator.js attached to whichever collection header existed
first. Boost-SD renders the header twice (static theme .collection-header at
first paint, then .boost-sd__collection-header hydrates async). The rotator
settled into the static theme header, set a started flag, and never re-homed,
so slides painted into an invisible container -> flat #1a1a1a hero band.

Fix (DTD verdict A, combined-abc, Codex+Claude 2/2): durable attach loop that
ALWAYS prefers Boost, RE-HOMES the same rotator node into the Boost header when
it hydrates (teardown timer -> move SAME node -> restart, never clone), and only
falls back to the theme header as final home after a ~4s grace when Boost is
provably absent. Idempotent; preserves reduced-motion, Page-Visibility pause,
preload-next, ~5.2s interval.

Verified high-fidelity against the LIVE served DOM (buggy markup already live):
post-Boost-hydration, deleted the mis-homed rotator, ran corrected attach logic.
ASSERT1 rotator.parentElement matches .boost-sd__collection-header=true; ASSERT2
active slide advances; ASSERT3 slide paints behind title pill; ASSERT4 two band
screenshots pixel-different (red->green crossfade confirmed visually).

PUSH-LIVE.sh: guard so an existing .pushbak (earliest known-good pre-fix live
snapshot) is never clobbered on re-run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit c9b7c05eb87aaa37a069c70e31e539a394fb8cc3
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jun 23 16:27:38 2026 -0700

    Fix collection rotating-hero hydration race: re-home rotator into Boost header
    
    Root cause: dw-hero-rotator.js attached to whichever collection header existed
    first. Boost-SD renders the header twice (static theme .collection-header at
    first paint, then .boost-sd__collection-header hydrates async). The rotator
    settled into the static theme header, set a started flag, and never re-homed,
    so slides painted into an invisible container -> flat #1a1a1a hero band.
    
    Fix (DTD verdict A, combined-abc, Codex+Claude 2/2): durable attach loop that
    ALWAYS prefers Boost, RE-HOMES the same rotator node into the Boost header when
    it hydrates (teardown timer -> move SAME node -> restart, never clone), and only
    falls back to the theme header as final home after a ~4s grace when Boost is
    provably absent. Idempotent; preserves reduced-motion, Page-Visibility pause,
    preload-next, ~5.2s interval.
    
    Verified high-fidelity against the LIVE served DOM (buggy markup already live):
    post-Boost-hydration, deleted the mis-homed rotator, ran corrected attach logic.
    ASSERT1 rotator.parentElement matches .boost-sd__collection-header=true; ASSERT2
    active slide advances; ASSERT3 slide paints behind title pill; ASSERT4 two band
    screenshots pixel-different (red->green crossfade confirmed visually).
    
    PUSH-LIVE.sh: guard so an existing .pushbak (earliest known-good pre-fix live
    snapshot) is never clobbered on re-run.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 shopify/collection-hero-fix/PUSH-LIVE.sh              | 9 ++++++++-
 shopify/collection-hero-fix/verify-rehome-live-dom.js | 7 +++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/shopify/collection-hero-fix/PUSH-LIVE.sh b/shopify/collection-hero-fix/PUSH-LIVE.sh
index 6531b382..8adba83b 100644
--- a/shopify/collection-hero-fix/PUSH-LIVE.sh
+++ b/shopify/collection-hero-fix/PUSH-LIVE.sh
@@ -28,8 +28,15 @@ def put(k,v):
     s=json.load(urllib.request.urlopen(urllib.request.Request(f"https://{STORE}/admin/api/2024-10/themes/{LIVE}/assets.json",data=body,method='PUT',headers={'X-Shopify-Access-Token':tok,'Content-Type':'application/json'})))['asset']['size']
     print('  PUT',k,s,'bytes'); time.sleep(2)
 B='shopify/collection-hero-fix'
+import os
 for k in ['assets/custom.css','sections/collection.liquid','config/settings_schema.json']:
-    open(f"{B}/backups/{k.replace('/','_')}.live-{LIVE}.pushbak",'w').write(get(k)); print('  backup',k)
+    bp=f"{B}/backups/{k.replace('/','_')}.live-{LIVE}.pushbak"
+    if os.path.exists(bp):
+        # NEVER clobber an existing .pushbak — it holds the earliest known-good
+        # pre-fix live snapshot (the clean dark band). Re-runs preserve it.
+        print('  backup',k,'(kept existing .pushbak, not overwritten)')
+    else:
+        open(bp,'w').write(get(k)); print('  backup',k)
 put('snippets/dw-collection-hero-bg.liquid', open(f'{B}/snippets_dw-collection-hero-bg.liquid').read())
 put('assets/dw-hero-rotator.js', open(f'{B}/dw-hero-rotator.js').read())
 put('sections/collection.liquid', open(f'{B}/patched/sections_collection.liquid').read())
diff --git a/shopify/collection-hero-fix/verify-rehome-live-dom.js b/shopify/collection-hero-fix/verify-rehome-live-dom.js
index 6f080bd5..22f2b38b 100644
--- a/shopify/collection-hero-fix/verify-rehome-live-dom.js
+++ b/shopify/collection-hero-fix/verify-rehome-live-dom.js
@@ -49,12 +49,15 @@ const ROTATOR_JS = fs.readFileSync(__dirname + '/dw-hero-rotator.js', 'utf8');
       var s = document.createElement('div');
       s.className = 'dw-hero-slide' + (i === 0 ? ' is-active' : '');
       s.setAttribute('data-dw-slide', String(i));
+      // IMPORTANT: do NOT set inline opacity — production slides (from the Liquid
+      // snippet) carry NO inline opacity; the staged .dw-hero-slide/.is-active CSS
+      // drives the crossfade. Inline opacity here would mask the rotator's class
+      // toggling and falsely look "stuck". Match production exactly.
       var bg = u.charAt(0) === '#'
         ? u
         : "linear-gradient(180deg,rgba(0,0,0,0.18),rgba(0,0,0,0.34)),url('" + u + "')";
       var prop = u.charAt(0) === '#' ? 'background-color:' : 'background-image:';
-      s.style.cssText = 'position:absolute;inset:0;background-size:cover;opacity:' +
-        (i === 0 ? '1' : '0') + ';transition:opacity 400ms;' + prop + bg + ';';
+      s.style.cssText = prop + bg + ';';
       rot.appendChild(s);
     });
     // Insert above the theme .collection-header (snippet's pre-hydration position).

← 8eb976d7 fix(theme): unhide DW density/grid slider on collection page  ·  back to Designer Wallcoverings  ·  Close dedup-specs audit: 0.17% duplication (5/3000) — catalo a08ffaa0 →