PageSourceSearch

https://www.taurist.com/conversion-static/HeroScene.jsx

js taurist.com collected 2026-10-08 20:47:57 UTC 4,253 bytes, 105 lines download raw bytes

1// HeroScene.jsx — looping hero visual for Conversion Works.
2// A central "YOUR WEBSITE" device powers on first; then, one surface at a time,
3// a connector arrow draws toward a CRO card and that card loads in. The order
4// sweeps around the device: top-left → middle-left → bottom-left → bottom →
5// bottom-right → middle-right → top-right. After the full state, it holds, then
6// loops. Cards are transparent cutouts (normal blend); arrows are glow-on-black
7// (screen blend). Honors prefers-reduced-motion (everything shown at rest).
8
9const HS_A = (p) => assetUrl("assets/hero-scene/" + p);
10
11const HS_CARDS = [
12  { k: "card-pdp-v3.avif",        cls: "hs-pdp" },
13  { k: "card-checkout-v3.avif",   cls: "hs-checkout" },
14  { k: "card-reviews-v3.avif",    cls: "hs-reviews" },
15  { k: "card-heatmap-v3.avif",    cls: "hs-heatmap" },
16  { k: "card-cart-v3.avif",       cls: "hs-cart" },
17  { k: "card-tracking-v3.avif",   cls: "hs-tracking" },
18  { k: "card-analytics-v3.avif",  cls: "hs-analytics" },
19];
20
21// connector arrows — each art-on-black asset bridges its card to the central device.
22const HS_STREAKS = [
23  { k: "arrow-pdp.avif",       cls: "hs-ar-pdp" },
24  { k: "arrow-cart.avif",      cls: "hs-ar-cart" },
25  { k: "arrow-heatmap.avif",   cls: "hs-ar-heatmap" },
26  { k: "arrow-checkout.avif",  cls: "hs-ar-checkout" },
27  { k: "arrow-reviews.avif",   cls: "hs-ar-reviews" },
28  { k: "arrow-tracking.avif",  cls: "hs-ar-tracking" },
29  { k: "arrow-analytics.avif", cls: "hs-ar-analytics" },
30];
31
32// reveal order: device, then arrow→card around the layout. Keys match the class
33// suffix after "hs-" (e.g. card "hs-pdp" → "pdp", arrow "hs-ar-pdp" → "ar-pdp").
34const HS_ORDER = [
35  "tablet",
36  "ar-pdp", "pdp",
37  "ar-heatmap", "heatmap",
38  "ar-reviews", "reviews",
39  "ar-tracking", "tracking",
40  "ar-analytics", "analytics",
41  "ar-checkout", "checkout",
42  "ar-cart", "cart",
43];
44
45// per-key reveal time (ms). The card loads almost the instant its arrow lands, and
46// the next arrow follows a split-second later — no empty beats.
47const HS_TIMING = (() => {
48  const t = { tablet: 250 };
49  const pairs = ["pdp", "heatmap", "reviews", "tracking", "analytics", "checkout", "cart"];
50  pairs.forEach((p, i) => {
51    const arrow = 480 + i * 290;   // next arrow fires before the previous card finishes
52    t["ar-" + p] = arrow;
53    t[p] = arrow + 90;             // card loads right behind its arrow
54  });
55  return t;
56})();
57const HS_LOOP_AT = 480 + 6 * 290 + 90 + 3200;  // last card + ~3.2s hold, then loop
58
59function HeroScene() {
60  const reduce = typeof window !== "undefined" && window.matchMedia &&
61    window.matchMedia("(prefers-reduced-motion: reduce)").matches;
62  const [shown, setShown] = useState(() => reduce ? new Set(HS_ORDER) : new Set());
63
64  useEffect(() => {
65    if (reduce) return;
66    let timers = [];
67    const run = () => {
68      setShown(new Set());
69      HS_ORDER.forEach((key) => {
70        timers.push(setTimeout(() => {
71          setShown((prev) => { const n = new Set(prev); n.add(key); return n; });
72        }, HS_TIMING[key]));
73      });
74      timers.push(setTimeout(run, HS_LOOP_AT));
75    };
76    const start = setTimeout(run, 300);
77    timers.push(start);
78    return () => timers.forEach(clearTimeout);
79  }, []);
80
81  const sc = (cls) => cls.replace("hs-", ""); // class → reveal key
82
83  return (
84    <div className="hs-box" aria-hidden="true">
85      <div className="hs-haze" />
86      <div className="hs-slab" />
87      <img className="hs-beam hs-beam-top" src={assetUrl("assets/hero-beam-purple.avif")} alt="" />
88      <img className="hs-beam hs-beam-bottom" src={assetUrl("assets/hero-beam-purple.avif")} alt="" />
89      <div className="hs-scene">
90        {HS_STREAKS.map((s) => (
91          <img key={s.k} src={HS_A(s.k)} alt=""
92            className={"hs-streak " + s.cls + (shown.has(sc(s.cls)) ? " is-shown" : "")} />
93        ))}
94        <img className={"hs-tablet" + (shown.has("tablet") ? " is-shown" : "")}
95          src={HS_A("tablet-1920.avif")} alt="" />
96        {HS_CARDS.map((c) => (
97          <img key={c.k} src={HS_A(c.k)} alt=""
98            className={"hs-card " + c.cls + (shown.has(sc(c.cls)) ? " is-s
98hown" : "")} />
99        ))}
100      </div>
101    </div>
102  );
103}
104
105Object.assign(window, { HeroScene });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.