File size: 4,550 Bytes
8cf5139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"use client";
import { useEffect } from "react";

/**
 * VideoPerformance β€” mounts once in the root layout.
 *
 * What it does:
 * 1. visibilitychange β†’ pauses every <video> on the page when tab goes background,
 *    resumes only those inside the viewport when tab returns.
 * 2. IntersectionObserver β†’ watches every <video> added to the DOM at any time
 *    (MutationObserver + initial scan). Plays when β‰₯15% visible, pauses otherwise.
 * 3. CSS animation budget β†’ injects a <style> that sets animation-play-state:paused
 *    on the <html> element when the tab is hidden, stopping ALL CSS animations
 *    (squad scroll, orb spin, gold shimmer, etc.) with zero JS per-frame cost.
 *    Removes the rule when the tab returns.
 * 4. Reduced-motion respect β†’ if the user has prefers-reduced-motion enabled,
 *    all CSS animations are permanently paused.
 */
export default function VideoPerformance() {
  useEffect(() => {
    // ── 1. Inject animation-pause stylesheet ──────────────────────────────────
    const styleEl = document.createElement("style");
    styleEl.id = "__beryl_perf__";
    styleEl.textContent = `
      html.tab-hidden * { animation-play-state: paused !important; }
      @media (prefers-reduced-motion: reduce) {
        * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
      }
    `;
    document.head.appendChild(styleEl);

    // ── 2. Per-video IntersectionObserver ─────────────────────────────────────
    const observed = new Set<HTMLVideoElement>();

    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          const v = e.target as HTMLVideoElement;
          if (e.isIntersecting) {
            // Ensure GPU layer is set before playing
            if (!v.style.transform) v.style.transform = "translateZ(0)";
            if (!v.style.willChange) v.style.willChange = "transform";
            v.play().catch(() => {});
          } else {
            v.pause();
          }
        });
      },
      { threshold: 0.15, rootMargin: "0px 0px 100px 0px" }
    );

    const observeVideo = (v: HTMLVideoElement) => {
      if (observed.has(v)) return;
      observed.add(v);
      // Force GPU layer on every video we touch
      v.style.transform = "translateZ(0)";
      v.style.willChange = "transform";
      v.style.backfaceVisibility = "hidden";
      io.observe(v);
    };

    // Observe all existing videos
    document.querySelectorAll<HTMLVideoElement>("video").forEach(observeVideo);

    // Watch for videos added dynamically (e.g. lazy-loaded sections)
    const mo = new MutationObserver((mutations) => {
      mutations.forEach((m) => {
        m.addedNodes.forEach((node) => {
          if (node instanceof HTMLVideoElement) observeVideo(node);
          if (node instanceof Element) {
            node.querySelectorAll<HTMLVideoElement>("video").forEach(observeVideo);
          }
        });
      });
    });
    mo.observe(document.body, { childList: true, subtree: true });

    // ── 3. Tab visibility β†’ pause ALL / resume visible ────────────────────────
    const onVisibility = () => {
      if (document.hidden) {
        document.documentElement.classList.add("tab-hidden");
        observed.forEach((v) => v.pause());
      } else {
        document.documentElement.classList.remove("tab-hidden");
        observed.forEach((v) => {
          const r = v.getBoundingClientRect();
          if (r.top < window.innerHeight && r.bottom > 0) {
            v.play().catch(() => {});
          }
        });
      }
    };
    document.addEventListener("visibilitychange", onVisibility);

    // ── 4. iOS first-gesture unlock ───────────────────────────────────────────
    const onGesture = () => {
      observed.forEach((v) => {
        const r = v.getBoundingClientRect();
        if (r.top < window.innerHeight && r.bottom > 0) v.play().catch(() => {});
      });
    };
    document.addEventListener("touchstart", onGesture, { once: true });

    return () => {
      io.disconnect();
      mo.disconnect();
      document.removeEventListener("visibilitychange", onVisibility);
      document.removeEventListener("touchstart", onGesture);
      styleEl.remove();
    };
  }, []);

  return null;
}