Lazy image with default Resux placeholder
lazy loading="lazy" :placeholder="true" placeholderClass="bg-slate-800/70"
Resux Media QA
Responsive media regression page for lazy loading, placeholders, fallback behavior, cache URLs, and quality/format handling. Open browser network tab and verify lazy assets are not requested before scrolling into view.
Cache URL (1d)
/_resux/generated/images/5b7bbd2f.webp?src=%2Fmedia-test%2Fimages%2Fhero-large.webp&original=%2Fmedia-test%2Fimages%2Fhero-large.jpg&w=1400&q=88&f=webp&cache=1d
Cache URL (7d)
/_resux/generated/images/c1933d20.avif?src=%2Fmedia-test%2Fimages%2Fhero-square.avif&original=%2Fmedia-test%2Fimages%2Fhero-square.jpg&w=1200&q=90&f=avif&cache=7d
No Format/Quality URL
/_resux/generated/images/752c32f6.jpeg?src=%2Fmedia-test%2Fimages%2Fhero-large.jpg&w=1200&cache=1d
ResuxImg
Lazy image with default Resux placeholder
lazy loading="lazy" :placeholder="true" placeholderClass="bg-slate-800/70"
Lazy image with custom placeholder image
lazy placeholder="/media-test/images/custom-placeholder.jpg"
Lazy image with text placeholder
lazy placeholder="Loading image..."
Eager image with no placeholder
loading="eager" placeholder=undefined
Image with fallbackSrc configured
src="/media-test/images/hero-wide.jpg" fallbackSrc="/media-test/images/hero-square.jpg" width="860" fit="cover"
Image with placeholder only
src="/media-test/images/hero-large.jpg" lazy :placeholder="true"
format=undefined, quality=undefined
:format="undefined" :quality="undefined" modifiers={ format:false, quality:false }
format=null, quality=null
:format="null" :quality="null" modifiers={ format:false, quality:false }
format="", quality=""
format="" quality="" modifiers={ format:false, quality:false }
Cached transformed image
format="webp" quality=88 cache="1d"
Original vs transformed quality comparison
format=null quality=null vs explicit format="webp" quality=88
ResuxPicture
Lazy picture with default Resux placeholder
lazy :placeholder="true" placeholderClass="bg-slate-800/60" formats="avif,webp,jpg"
Lazy picture with custom placeholder image
lazy placeholder="/media-test/images/custom-placeholder.jpg"
Lazy picture with text placeholder
lazy placeholder="Loading picture..."
Picture with multiple source definitions
:sources="[{ src, format:'webp', media:'(min-width:768px)' }, { src, format:null, media:'(max-width:767px)' }]"
Picture with fallback configuration
src="/media-test/images/hero-large.jpg" fallback="/media-test/images/hero-square.jpg" fallbackSrc="/media-test/images/hero-square.jpg"
Picture format=null (no conversion)
:format="null" :quality="88" modifiers={ format:false }
Picture quality=null (no compression)
formats="webp,jpg" :quality="null" modifiers={ quality:false }
Cached transformed picture
formats="avif,webp,jpg" quality=88 cache="7d"
Non-cached transformed picture
formats="webp,jpg" quality=88 :cache="false"
ResuxVideo
Eager video with controls
src + controls + preload="metadata"Lazy video with poster
lazy poster controlsLazy video with themed custom controls
lazy controls controlsAccent="#22d3ee" controlsBackground="rgba(15,23,42,.80)" controlsColor="#f8fafc"Lazy video with default Resux placeholder
lazy :placeholder="true" controlsLazy video with skeleton placeholder
lazy placeholder="/media-test/videos/placeholder.jpg"Lazy video with custom placeholder image
lazy placeholder="/media-test/images/custom-placeholder.jpg"Lazy video with text placeholder
lazy placeholder="Loading video..."Lazy autoplay muted loop video
lazy autoplay muted loop playsinlineLazy video with multiple sources
:sources="[{ src:'/sample-video-alt.mp4', type:'video/mp4' }, { src:'/sample-video.mp4', type:'video/mp4' }]"Lazy video with speed control
lazy controls speedControl :speeds="[0.5, 0.75, 1, 1.25, 1.5, 2]" :defaultSpeed="1"Lazy video inside responsive card grid
lazy aspect-ratio="16 / 9" class="card media"Video with fallback poster configuration
src="/media-test/videos/sample-video.mp4" fallbackPoster="/media-test/videos/sample-poster.jpg"Video quality setting control test (in-video UI)
quality-control + :qualities + speed-control inside ResuxVideo overlay
Quality and speed controls are rendered inside the video UI. Switching quality should update source selection in-place without a full-page reload.
ResuxVideo Advanced
Advanced runtime checks for click-to-skip zones, hero/preload hints, and poster-first deferred loading. Expected behavior: no hard refresh, no scroll reset, no router navigation, and one reveal/load cycle per video.
Skip overlay controls (default 1s)
controls lazy skipControls :skipSeconds="1"Tap/click left half to skip backward and right half to skip forward by 10s without any page refresh.
Skip overlay controls (back 5s, forward 15s)
skipControls :skipBackwardSeconds="5" :skipForwardSeconds="15" skipLabel="Jump"Left/right click zones should skip by different durations and never trigger router navigation.
Hero priority preload mode
hero priority preloadLink :lazy="false" loading="eager"Hero video should render eager with high fetch priority and preload link, without hard refresh.
Chunk/range-friendly lazy mode
lazy chunkLoading preload="metadata"Uses metadata-first loading hints and lazy reveal to reduce heavy initial transfers.
Poster-first then page-ready chunk loading
deferUntilPageReady revealOnPageReady chunkLoading posterStarts as poster/placeholder first, then reveals video load after full page ready with no reload.
Hero + defer + chunk + skip combo
hero deferUntilPageReady chunkLoading skipControls :skipSeconds="5"Combines hero hints, deferred chunk loading, and skip controls while keeping SPA runtime stable.
ResuxVideo Capability Matrix
This section validates all supported ResuxVideo behavior in grouped scenarios A-K. Groups are collapsible and mounted on demand to keep initial page load lighter while still covering lazy reveal, controls, fallbacks, speed, quality, and runtime navigation behavior.
1. Basic MP4 video
src="/media-test/videos/sample-video.mp4" controlsExpected: MP4 plays with controls.
2. Basic WebM video
src="/media-test/videos/sample-video.webm" controlsExpected: WebM source should play directly.
3. Multiple sources: WebM first, MP4 fallback
:sources="[{webm},{mp4}]" controlsExpected: browser tries WebM then MP4 fallback without navigation.
4. Video with poster
poster="/media-test/videos/sample-poster.jpg"Expected: poster is visible before playback.
5. Video without poster
no poster propExpected: loads without poster image and no navigation.
6. Video with controls
controlsExpected: controls are visible and interactive.
7. Video without controls
:controls="false"Expected: no controls UI rendered.
1. Eager video
:lazy="false" loading="eager"Expected: requests on initial render.
2. Lazy video
lazy loading="lazy"Expected: request starts only near viewport.
3. Lazy video far below fold
lazy + spacerExpected: no request until deep scroll.
4. Lazy video custom rootMargin
root-margin="900px 0px"Expected: reveals early via rootMargin.
5. Lazy video custom threshold
threshold="0.4"Expected: waits for more visibility before reveal.
6. Lazy video preload=none
lazy preload="none"Expected: remains none until reveal logic runs.
7. Lazy preload metadata after reveal
lazy preload="metadata"Expected: SSR uses preload=none, reveal flips to metadata.
8. Eager preload metadata
loading="eager" preload="metadata"Expected: metadata preload on initial render.
9. Eager preload auto
loading="eager" preload="auto"Expected: auto preload without route navigation.
1. Muted autoplay loop video
autoplay muted loopExpected: loops silently with autoplay policy compliance.
2. Muted autoplay playsinline
autoplay muted playsinlineExpected: inline autoplay on supported devices.
3. Loop-only video
loopExpected: loops when user starts playback.
4. Muted-only video
mutedExpected: starts muted; no navigation side effects.
5. Playsinline-only video
playsinlineExpected: requests inline playback mode.
6. Video respecting prefers-reduced-motion
autoplay muted :force-autoplay="false"Expected: autoplay is skipped under reduced motion.
7. Video with forceAutoplay
autoplay muted :force-autoplay="true"Expected: autoplay attempted even with reduced motion setting.
1. 16:9 video
aspect-ratio="16 / 9"Expected: widescreen ratio maintained.
2. 4:3 video
aspect-ratio="4 / 3"Expected: 4:3 frame preserved.
3. 1:1 square video
aspect-ratio="1 / 1"Expected: square container.
4. Portrait video container
aspect-ratio="9 / 16"Expected: portrait layout container.
5. Full-width responsive video
class="w-full"Expected: fills container width responsively.
6. Video inside card grid
card grid containerExpected: stable sizing in grid.
7. Video inside narrow mobile-like container
max-width: 360pxExpected: no horizontal overflow in narrow container.
8. Video with fixed width/height
:width="640" :height="360"Expected: fixed dimensions respected.
9. Video with CSS class override
class="ring-2 ring-emerald-400"Expected: class styling applies cleanly.
10. Video with inline style override
style="border-radius:24px; box-shadow:..."Expected: inline style override applies.
1. placeholder=true default Resux logo
placeholderExpected: default placeholder logo before reveal.
2. Custom image placeholder
placeholder="/media-test/videos/placeholder.jpg"Expected: custom image placeholder visible.
3. Text placeholder
placeholder="Loading video..."Expected: text placeholder visible.
4. Skeleton placeholder
placeholder="/media-test/videos/placeholder.jpg"Expected: skeleton-like placeholder image.
5. Poster only
poster="/media-test/videos/sample-poster.jpg"Expected: poster shown before playback.
6. Poster with fallbackPoster
poster + fallbackPosterExpected: fallbackPoster available for error path.
7. Broken poster with fallbackPoster
poster=missing fallbackPoster=validExpected: fallbackPoster takes over.
8. Broken poster with placeholder
poster=missing placeholder=trueExpected: placeholder remains visible.
9. Broken video with fallbackPoster
src=missing fallbackPoster=validExpected: fallbackPoster after error, no reload.
10. Broken video with text placeholder
src=missing placeholder="Video unavailable"Expected: text placeholder/fallback state shown.
11. Broken video with default logo placeholder
src=missing placeholder=trueExpected: default placeholder persists on error.
1. Multiple sources eager
:lazy="false" :sources="[webm,mp4]"Expected: eager source resolution without router activity.
2. Multiple sources lazy
lazy :sources="[webm,mp4]"Expected: no source requests before reveal.
3. Multiple sources with poster
poster + sourcesExpected: poster shown while choosing source.
4. Multiple sources with placeholder
placeholder + sourcesExpected: placeholder shown pre-reveal.
5. First source missing, second works
sources=[missing,mp4]Expected: first failure then second source works.
6. All sources fail + fallback placeholder
sources=[missing,missing] fallbackPoster+placeholderExpected: fallback placeholder state, no retry loop.
7. No requests before lazy reveal
lazy + sources + root-margin="0px"Expected: source requests start only on intersection.
8. No duplicate source requests after navigation
lazy + sources + debug attrsExpected: one reveal/load cycle after route return.
1. Speed control with default speeds
speed-controlExpected: default speeds cycle in control.
2. Speed control custom speeds
speed-control :speeds="[0.25,0.5,1,1.25,1.5,2]"Expected: custom list cycles in order.
3. Speed defaultSpeed=1.25
speed-control :default-speed="1.25"Expected: initial speed label starts at 1.25x.
4. showSpeedIcon=false
speed-control :show-speed-icon="false"Expected: speed text shown without icon.
5. Custom speed label
speed-control speed-label="Rate"Expected: button aria label uses custom text.
6. Speed control on lazy video
lazy speed-controlExpected: speed works after lazy reveal.
7. Speed control on eager video
:lazy="false" loading="eager" speed-controlExpected: speed control works eagerly.
8. Speed control after client-side navigation
speed-control + debugExpected: still one controls init after returning to /media.
9. Speed control must not hard refresh
speed-controlExpected: clicking speed never reloads page.
10. Speed control must not trigger router nav
speed-controlExpected: speed clicks are ignored by router interceptor.
1. Quality selector enabled
quality-control + :qualities (in-player)Expected: selecting quality swaps source in-place.
2. Quality selector with defaultQuality
default quality = 720pExpected: starts on configured default quality.
3. Quality selector without defaultQuality
no default, first option fallbackExpected: first quality option used.
4. 360p/720p/1080p assets
sample-360/sample-720/sample-1080Expected: all local quality assets are selectable.
5. One missing quality source
include missing quality URLExpected: missing quality handled without reload.
6. Advanced per-quality sources
webm+mp4 for each qualityExpected: format fallback works per selected quality.
7. Quality selector on lazy video
lazy + selectorExpected: no request until reveal.
8. Quality selector on eager video
eager + selectorExpected: selected source loads eagerly.
9. Quality switch preserves time
capture currentTime and restoreExpected: time is restored after switch.
10. Quality switch resumes if playing
capture paused stateExpected: auto-resume only when previously playing.
11. Quality switch no hard refresh
selector interactionsExpected: no document reload.
12. Quality switch no router nav
in-player selector + controlsExpected: no route navigation.
13. Quality control after navigation
navigate away/backExpected: selector and video still function.
14. Far-below-fold quality control
quality harness below spacerExpected: delayed loading until deep scroll.
Quality harness: selector + preserve-time + resume-if-playing
buttons/select switch quality -> capture currentTime + playing state -> remount -> restore
Expected: switching quality should not hard refresh, should preserve approximate playback time, and resume only if the video was already playing.
Manual check: use in-video quality selector while playing and verify time continuity and playback resume behavior.
1. Speed + quality controls together
speed-control + quality-control (in-player)Expected: both controls coexist.
2. Speed + quality + lazy
lazy + speed-control + quality-controlExpected: lazy reveal then both controls work.
3. Speed + quality + poster
poster + controlsExpected: poster shown before load.
4. Speed + quality + placeholder
placeholder + controlsExpected: placeholder behavior maintained.
5. Speed + quality + multiple formats
webm+mp4 per qualityExpected: format fallback preserved.
6. Speed + quality + broken source fallback
quality includes missing URLExpected: broken quality path handled safely.
7. Speed + quality in responsive grid
grid layoutExpected: controls stay usable in grid.
8. Speed + quality far below fold
spacer + lazyExpected: delayed load + controls still functional.
Combined harness: speed + quality + lazy + poster + placeholder
quality selector + speedControl + lazy + format fallback (webm/mp4) + error quality option
Expected: speed and quality controls can be used together without router navigation, hard refresh, or duplicate loading loops.
1. Missing video source
src="/media-test/videos/missing-video.mp4"Expected: error state + fallback path, no reload.
2. Missing first source, valid second source
sources=[missing,mp4]Expected: second source used.
3. Missing all sources
sources=[missing,missing]Expected: fallback placeholder state, no loops.
4. Invalid video URL
src="/media-test/videos/%%%bad%%%.mp4"Expected: handled as error without navigation.
5. Empty src
src=""Expected: no crash and no route navigation.
6. src=null
:src="null"Expected: no source assignment; stable UI.
7. sources=[]
:sources="[]"Expected: handles empty sources array safely.
8. qualities=[] (selector harness)
quality options = []Expected: selector disabled safely.
9. Missing selected defaultQuality
default quality not in optionsExpected: fallback quality chosen.
10. Invalid selected quality source
quality url missingExpected: error fallback and no hard refresh.
11. Broken poster
poster=missingExpected: poster fail does not reload app.
12. Broken fallbackPoster
fallbackPoster=missingExpected: placeholder path still safe.
13. Error must not retry forever
broken source + observe networkExpected: one failure path, no infinite retries.
14. Error must not hard refresh
broken sourceExpected: no document reload.
15. Error must not duplicate video.load()
broken source + lazyExpected: no repeated load loop for same failed source.
1. Direct load /media
open /media directlyExpected: no hard refresh while revealing videos.
2. Navigate away and back to /media
use app linksExpected: videos initialize once and still lazy-load correctly.
3. Browser back/forward
history back/forwardExpected: no duplicate observers or listeners.
4. Scroll into video section after navigation
navigate then scrollExpected: in-place reveal only.
5. Speed control after navigation
change route then adjust speedExpected: speed control still works without reload.
6. Quality control after navigation
change route then quality switchExpected: quality switch still works safely.
7. Far-below-fold lazy video after navigation
navigate back then deep scrollExpected: loads when near viewport.
8. No duplicate observers after navigation
inspect data-resux-observedExpected: one observation cycle per element.
9. No duplicate listeners after navigation
interact controls repeatedlyExpected: no multi-fire handler behavior.
10. No hard refresh at any point
watch network + scroll positionExpected: no full document reload.
Manual navigation/runtime checklist
direct load /media -> navigate away/back -> browser back/forward -> deep scroll -> speed/quality interactions
Lazy Network Check
The spacer below keeps this example off-screen initially. Confirm in network tab that the video request starts only after scroll.
Lazy video far down page
lazy loading="lazy" root-margin="0px 0px" threshold="0.01"