Appearance
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/lastStartedVideoIndexprops $emit('video-timeupdate')and$emit('video-ended')added to CreativeVideoBlock- VideoConfiguration crash fixed (
getBlockByNameused full path instead of blockName) - Video upload race condition fixed (batched 3 sequential
updateSlideOverrideinto single clone+emit)
Video-based autoplay timing (CE)
effectiveTimerProgressdrives timer dots from video progress for video slides- rAF timer for non-video slides
- Video ending auto-advances to next slide
AF config changes
allowedSubBlocksincludesBLOCKS.VIDEOin SliderV2 defaults- SlideSection extended with video override template, hidden toggle, and helper methods
- VideoConfiguration extracts
blockNamefrompath.split('.').pop()for sub-block support
Scroll mode — partial fix
- Reactive
scrollSnapOverridesurvives Vue re-renders (unlike direct DOM mutation) isProgrammaticScrollingflag blocksonScrollduring 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
startPosis 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):
- Direct DOM
track.style.scrollSnapType = 'none'— Vue re-renders overwrote it - Reactive
scrollSnapOverride+$nextTick+ nativescrollTo({behavior: 'smooth'})—scroll-snap-stop: alwaysforces pause at every snap point - 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
scrollToorscrollLeftanimation 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
slidemode (translateX on a track-inner wrapper) - Or: for scroll mode specifically, use
scrollBywith 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'andoverflow: 'hidden'are set on slide faces-cube-scenehasbackgroundPropertiesapplied (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-slidein 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/removeChildBlockinstead 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)
6717a03fix: disable scroll-snap during programmatic scroll68a9ab9fix: use reactive scrollSnapType to survive Vue re-renders4c8b20efix: defer scrollTo to $nextTickf7b40f4feat: render video through sub-block loop with video-based autoplay timing61e4199fix: scroll mode arrow navigation — set activeIndex immediately349c8befix: replace native scrollTo with rAF animation865dd5cfix: capture scroll position before reactive changes, handle loop swipe
AF (Application-Frontend)
578c8fefix: batch video upload overrides491c391feat: allow video block as SliderV2 sub-block6f23342feat: extend SlideSection for video sub-blocks with per-slide hidden toggle19f2b61fix: extract blockName from path in VideoConfiguration
Key files
| File | Repo | Purpose |
|---|---|---|
src/components/creative/CreativeSliderBlockV2/CreativeSliderBlockV2.vue | CE | Main slider runtime (~2000 lines) |
src/components/creative/CreativeVideoBlock/CreativeVideoBlock.vue | CE | Video block (emits timeupdate/ended) |
src/pages/.../Configuration/components/SlideSection.vue | AF | Slide override config (video, hidden toggle) |
src/pages/.../Configuration/configs/VideoConfiguration.vue | AF | Video config (blockName fix for sub-blocks) |
src/pages/.../Blocks/data/defaults.ts | AF | SliderV2 defaults (allowedSubBlocks) |