Skip to content

SliderV2 Phase 5 — Video Sub-block & Scroll Fixes

Branch: add-slider-v2 (both AF and CE) Date: 2026-03-13


DONE (implemented & tested working)

Video as sub-block (CE + AF)

  • Video renders through sub-block loop via CreativeVideoBlock (not hardcoded <video> overlay)
  • Removed all 4 hardcoded <video> elements from cube/carousel/slide/default templates
  • Per-slide video override (swap video per slide via FileUploader in SlideSection)
  • Per-slide hidden toggle (eye icon, works for any sub-block type)
  • Video lifecycle (play/pause) controlled via instanceIndex/lastStartedVideoIndex props
  • $emit('video-timeupdate') and $emit('video-ended') added to CreativeVideoBlock
  • VideoConfiguration crash fixed (getBlockByName used full path instead of blockName)
  • Video upload race condition fixed (batched 3 sequential updateSlideOverride into single clone+emit)

Video-based autoplay timing (CE)

  • effectiveTimerProgress drives timer dots from video progress for video slides
  • rAF timer for non-video slides
  • Video ending auto-advances to next slide

AF config changes

  • allowedSubBlocks includes BLOCKS.VIDEO in SliderV2 defaults
  • SlideSection extended with video override template, hidden toggle, and helper methods
  • VideoConfiguration extracts blockName from path.split('.').pop() for sub-block support

Scroll mode — partial fix

  • Reactive scrollSnapOverride survives Vue re-renders (unlike direct DOM mutation)
  • isProgrammaticScrolling flag blocks onScroll during programmatic navigation
  • rAF-driven scroll animation (bypasses native scroll-snap-stop: always)
  • Touch events tracked in scroll mode for loop boundary detection

BUGS — Still open

B1: Scroll mode arrow/keyboard navigation broken

Severity: High Symptoms:

  • Clicking left arrow animates in the WRONG DIRECTION (forward instead of backward) but lands on correct slide
  • Clicking right arrow scrolls through ALL intermediate slides visually (looks like it starts from position 0)
  • Both symptoms suggest startPos is being read incorrectly despite pre-capture fix

Root cause hypothesis: Vue's StyleAndClassNameGenerationMixin watcher does clearStyleElement() (sets innerHTML='') then rebuilds CSS. Even though these are synchronous, reading track.scrollLeft after the reactive flush may force a browser layout recalculation where the cleared styles briefly took effect. The pre-capture approach (capturing startPos before reactive changes) may not fully solve this if the $nextTick restore of scrollLeft races with the browser's layout.

Attempted fixes (3 iterations):

  1. Direct DOM track.style.scrollSnapType = 'none' — Vue re-renders overwrote it
  2. Reactive scrollSnapOverride + $nextTick + native scrollTo({behavior: 'smooth'})scroll-snap-stop: always forces pause at every snap point
  3. rAF animation with pre-captured startPos + restore in $nextTick — still wrong direction/position

Suggested next approach:

  • Consider treating arrow clicks like native scroll: instead of using scrollTo or scrollLeft animation at all, simply let the native scroll handle it. This could mean:
    • Programmatically dispatching wheel/scroll events
    • Or: abandon native scroll for ALL programmatic navigation and use the same JS transform approach as slide mode (translateX on a track-inner wrapper)
    • Or: for scroll mode specifically, use scrollBy with pixel distance instead of absolute position, avoiding the startPos issue entirely

B2: Scroll mode loop doesn't work (finger scroll)

Severity: Medium Status: Touch boundary detection added but needs testing Details: Native CSS scroll can't wrap around. Touch handler detects swipe at first/last slide and calls scrollToSlide with wrapped index. Arrow loop works (instant jump). Finger scroll loop needs user testing to confirm.

B3: Cube mode visual artifacts

Severity: Medium Symptoms:

  • Red slider background leaks through during cube transitions
  • White/colored pieces visible around/behind the blue slide faces mid-rotation
  • User test: red background on Style tab, blue graphic block covering entire slide

Details:

  • backfaceVisibility: 'hidden' and overflow: 'hidden' are set on slide faces
  • -cube-scene has backgroundProperties applied (this may be the red showing through)
  • Sub-block rendering changes are functionally identical for non-video scenarios
  • May be pre-existing (not caused by video sub-block refactor)

Key styles to investigate:

  • -cube-viewport: overflow: visible, perspective
  • -cube-scene: transformStyle: preserve-3d, background properties
  • -slide in cube: backfaceVisibility: hidden, overflow: hidden, background properties

B4: Fade/crossfade opacity issue

Severity: Low (likely pre-existing) Details: Slides appear semi-transparent during fade transitions. Our changes are functionally identical for non-video scenarios in the fade template, so this is likely a pre-existing issue.


TODO — Not yet started

T0: Adopt unified container block foundation (before merge)

SliderV2 is the ideal first adopter of the unified container block model described in architecture/unified-container-block-vision.md. Since V2 is not yet merged, there's zero migration risk.

Concrete changes before merge:

  • Fractional ordering: Use fractional order keys for sub-blocks instead of integers. Removes need for normalizeOrders.
  • Generic container mutations: Use addChildBlock / removeChildBlock instead of slider-specific mutations. Template creation becomes a hook that provides child defaults.
  • slides[] stays as-is: The per-slide override array is slider-specific data on the container, not part of the sub-block system. No change needed.

This avoids building ~2000 lines of new code on the old integer ordering system and then having to migrate later.

See: architecture/unified-container-block-vision.md (full vision), todos/BlockGrouping/ordering-bugs-and-fractional-indexing.md (ordering bugs + fractional indexing rationale)

T1: Slider V1 deprecation plan

  • How to communicate deprecation to users (toast/banner when V1 selected?)
  • Migration path: auto-convert V1 configs to V2?
  • Timeline: when stop allowing new V1 creatives? When remove V1 code?
  • V2 should be default/first choice in block picker

T2: Analytics audit

  • Verify all analytics events fire correctly in V2 (swipe, slide view, click-through)
  • Compare with V1 analytics to ensure parity

T3: Video analytics philosophy (discuss with Kevin — backend)

  • Per-video vs aggregated metrics when multiple slides have video
  • Per-video seems more useful but needs backend feasibility discussion
  • See detailed options in AF/todos/SliderV2/slider-v2-issues-and-features.md

Key commits (this session)

CE (Creative-Engine)

  • 6717a03 fix: disable scroll-snap during programmatic scroll
  • 68a9ab9 fix: use reactive scrollSnapType to survive Vue re-renders
  • 4c8b20e fix: defer scrollTo to $nextTick
  • f7b40f4 feat: render video through sub-block loop with video-based autoplay timing
  • 61e4199 fix: scroll mode arrow navigation — set activeIndex immediately
  • 349c8be fix: replace native scrollTo with rAF animation
  • 865dd5c fix: capture scroll position before reactive changes, handle loop swipe

AF (Application-Frontend)

  • 578c8fe fix: batch video upload overrides
  • 491c391 feat: allow video block as SliderV2 sub-block
  • 6f23342 feat: extend SlideSection for video sub-blocks with per-slide hidden toggle
  • 19f2b61 fix: extract blockName from path in VideoConfiguration

Key files

FileRepoPurpose
src/components/creative/CreativeSliderBlockV2/CreativeSliderBlockV2.vueCEMain slider runtime (~2000 lines)
src/components/creative/CreativeVideoBlock/CreativeVideoBlock.vueCEVideo block (emits timeupdate/ended)
src/pages/.../Configuration/components/SlideSection.vueAFSlide override config (video, hidden toggle)
src/pages/.../Configuration/configs/VideoConfiguration.vueAFVideo config (blockName fix for sub-blocks)
src/pages/.../Blocks/data/defaults.tsAFSliderV2 defaults (allowedSubBlocks)

Internal documentation