Skip to content

Commit 3bd8657

Browse files
mustbesimo2claude
andcommitted
fix: autoplay-veil guard — blocked videos hide behind their poster instead of showing Safari's native play glyph (Low Power Mode / per-site autoplay); first gesture starts playback
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7CWiDiLjSUPZL8XKVk6ZT
1 parent 36c668c commit 3bd8657

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

index.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,5 +916,35 @@ <h2 class="head reveal">Add it to your agent in one line.</h2>
916916
try { init(); } catch(e){ /* leave gradients */ }
917917
}
918918
</script>
919+
<script>
920+
/* autoplay-veil — a blocked video must never show Safari's native play glyph.
921+
Modern Safari (Low Power Mode, per-site Auto-Play settings) refuses even muted
922+
autoplay and paints a dark ▶ over the element; ::-webkit-media-controls-* hides
923+
are ignored. So every self-playing video starts invisible behind its own poster
924+
and unveils only on a real 'playing' event; first genuine gesture retries play.
925+
Opt out per-element with data-no-veil. */
926+
(function(){
927+
var vids=[].slice.call(document.querySelectorAll('video'));
928+
vids.forEach(function(v){
929+
if(v.dataset.noVeil!=null||v.controls)return;
930+
var auto=v.autoplay||v.hasAttribute('autoplay')||(v.muted&&v.loop)||v.hasAttribute('muted')&&v.hasAttribute('loop');
931+
if(!auto)return;
932+
var poster=v.getAttribute('poster'), ph=null;
933+
v.style.transition='opacity .8s ease'; v.style.opacity='0';
934+
if(poster){
935+
ph=document.createElement('img'); ph.src=poster; ph.alt=''; ph.setAttribute('aria-hidden','true');
936+
ph.style.cssText='position:absolute;inset:0;width:100%;height:100%;object-fit:cover;pointer-events:none;transition:opacity .8s ease;';
937+
var host=v.parentElement;
938+
if(host){ if(getComputedStyle(host).position==='static')host.style.position='relative';
939+
host.insertBefore(ph,v.nextSibling); }
940+
}
941+
function unveil(){ v.style.opacity='1'; if(ph)ph.style.opacity='0'; }
942+
if(!v.paused&&v.currentTime>0)unveil(); else v.addEventListener('playing',unveil);
943+
['pointerdown','touchstart','click','keydown'].forEach(function(t){
944+
addEventListener(t,function(){ if(v.paused){ v.muted=true; var p=v.play(); if(p&&p.catch)p.catch(function(){}); } },{passive:true});
945+
});
946+
});
947+
})();
948+
</script>
919949
</body>
920950
</html>

index.v2.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,5 +551,35 @@ <h2 class="head reveal">Add it to your agent in one line.</h2>
551551
}
552552
})();
553553
</script>
554+
<script>
555+
/* autoplay-veil — a blocked video must never show Safari's native play glyph.
556+
Modern Safari (Low Power Mode, per-site Auto-Play settings) refuses even muted
557+
autoplay and paints a dark ▶ over the element; ::-webkit-media-controls-* hides
558+
are ignored. So every self-playing video starts invisible behind its own poster
559+
and unveils only on a real 'playing' event; first genuine gesture retries play.
560+
Opt out per-element with data-no-veil. */
561+
(function(){
562+
var vids=[].slice.call(document.querySelectorAll('video'));
563+
vids.forEach(function(v){
564+
if(v.dataset.noVeil!=null||v.controls)return;
565+
var auto=v.autoplay||v.hasAttribute('autoplay')||(v.muted&&v.loop)||v.hasAttribute('muted')&&v.hasAttribute('loop');
566+
if(!auto)return;
567+
var poster=v.getAttribute('poster'), ph=null;
568+
v.style.transition='opacity .8s ease'; v.style.opacity='0';
569+
if(poster){
570+
ph=document.createElement('img'); ph.src=poster; ph.alt=''; ph.setAttribute('aria-hidden','true');
571+
ph.style.cssText='position:absolute;inset:0;width:100%;height:100%;object-fit:cover;pointer-events:none;transition:opacity .8s ease;';
572+
var host=v.parentElement;
573+
if(host){ if(getComputedStyle(host).position==='static')host.style.position='relative';
574+
host.insertBefore(ph,v.nextSibling); }
575+
}
576+
function unveil(){ v.style.opacity='1'; if(ph)ph.style.opacity='0'; }
577+
if(!v.paused&&v.currentTime>0)unveil(); else v.addEventListener('playing',unveil);
578+
['pointerdown','touchstart','click','keydown'].forEach(function(t){
579+
addEventListener(t,function(){ if(v.paused){ v.muted=true; var p=v.play(); if(p&&p.catch)p.catch(function(){}); } },{passive:true});
580+
});
581+
});
582+
})();
583+
</script>
554584
</body>
555585
</html>

0 commit comments

Comments
 (0)