Written by: Marlon Colca
Posted on 13 Sep 2025 - 21 days ago
nextjs typescript clones
Improve ergonomics with autoplay, best‑effort fullscreen, keyboard controls, and an optional “unmute” overlay.
Goal: Improve ergonomics with autoplay, best‑effort fullscreen, keyboard controls, and an optional “unmute” overlay.
src/hooks/useAutoFullscreen.ts
: tries requestFullscreen()
when playback starts.src/components/VideoPlayer.tsx
: sets autoPlay
(muted), enables autoFullscreen
, binds keys.// src/hooks/useAutoFullscreen.ts
export function useAutoFullscreen(
videoEl: HTMLVideoElement | null,
enable?: boolean
) {
useEffect(() => {
if (!videoEl || !enable) return;
let requested = false;
const tryFs = async () => {
if (requested) return;
requested = true;
try {
const anyVideo = videoEl as any;
if (!document.fullscreenElement && anyVideo.requestFullscreen)
await anyVideo.requestFullscreen();
else if (anyVideo.webkitEnterFullscreen)
anyVideo.webkitEnterFullscreen();
} catch {}
};
const onPlay = () => tryFs();
videoEl.addEventListener("play", onPlay);
if (!videoEl.paused) setTimeout(tryFs, 0);
return () => videoEl.removeEventListener("play", onPlay);
}, [videoEl, enable]);
}
// Inside VideoPlayer
useEffect(() => {
if (!videoEl) return;
const onKey = (e: KeyboardEvent) => {
const target = e.target as HTMLElement | null;
if (
target &&
(target.tagName === "INPUT" ||
target.tagName === "TEXTAREA" ||
target.isContentEditable)
)
return;
if (e.metaKey || e.ctrlKey || e.altKey) return;
switch (e.key) {
case " ":
case "k":
case "K":
e.preventDefault();
videoEl.paused ? void videoEl.play() : videoEl.pause();
break;
case "ArrowLeft":
e.preventDefault();
videoEl.currentTime = Math.max(0, videoEl.currentTime - 5);
break;
case "ArrowRight":
e.preventDefault();
videoEl.currentTime = Math.min(
videoEl.duration || Infinity,
videoEl.currentTime + 5
);
break;
case "m":
case "M":
e.preventDefault();
videoEl.muted = !videoEl.muted;
break;
case "f":
case "F":
e.preventDefault();
(document.fullscreenElement
? document.exitFullscreen?.()
: (videoEl as any).requestFullscreen?.()
)?.catch?.(() => {});
break;
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [videoEl]);
muted
automatically when autoPlay
is true.window
level for convenience; we skip when typing in inputs or when modifier keys are pressed.requestFullscreen
and webkitEnterFullscreen
.muted
is true and a user gesture occurs.e.target
for inputs/contentEditable.autoPlay
on: it should start muted; click “Tap to unmute”.Surface in‑progress items based on local resume data
14 Sep 2025 - 20 days ago