← back to Prestige Hyperframes Promo

my-video/index.html

151 lines

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=1920, height=1080" />
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      html, body { width: 1920px; height: 1080px; overflow: hidden; background: #05090f; }
      body { font-family: "Inter", "SF Pro Display", system-ui, sans-serif; color: #eaf2ff; }
      .full-bleed { position: absolute; inset: 0; width: 1920px; height: 1080px; }
      .fill-video { position: absolute; inset: 0; width: 1920px; height: 1080px; object-fit: cover; }
      .scene { position: absolute; inset: 0; display: flex; flex-direction: column;
               align-items: center; justify-content: center; text-align: center; }
      .eyebrow { font-weight: 800; font-size: 30px; letter-spacing: 8px; text-transform: uppercase; color: #38bdf8; }
      .title { font-weight: 900; font-size: 130px; line-height: 1; text-shadow: 0 10px 50px rgba(0,0,0,.6); }
      .sub { font-weight: 500; font-size: 40px; color: #c2d2e8; margin-top: 18px; }
      .left { align-items: flex-start; justify-content: flex-end; text-align: left; padding: 0 0 150px 110px; }
      .cat { display: inline-flex; align-items: center; gap: 12px; padding: 10px 20px; border-radius: 999px;
             background: rgba(56,189,248,.16); border: 1px solid rgba(56,189,248,.45);
             color: #38bdf8; font-weight: 800; font-size: 26px; letter-spacing: 3px; text-transform: uppercase; }
      .svc-name { font-weight: 900; font-size: 96px; margin-top: 20px; text-shadow: 0 8px 40px rgba(0,0,0,.8); }
      .price { font-weight: 900; font-size: 130px; line-height: .9; color: #38bdf8; text-shadow: 0 0 44px rgba(56,189,248,.5); }
      .scrim-lr { background: linear-gradient(90deg, rgba(5,9,15,.92) 0%, rgba(5,9,15,.45) 44%, rgba(5,9,15,0) 70%); }
      .stat { font-weight: 900; font-size: 76px; color: #eaf2ff; }
      .statlbl { font-weight: 600; font-size: 30px; color: #9fb3cd; letter-spacing: 1px; }
      .strike { position: absolute; left: 0; top: 54%; height: 12px; background: #fb7185; border-radius: 8px; }
      .row { display: flex; gap: 80px; margin-top: 44px; }
    </style>
  </head>
  <body>
    <div id="root" data-composition-id="main" data-start="0" data-duration="28"
         data-width="1920" data-height="1080">

      <!-- shared animated background (NOT a clip) -->
      <div id="bg" class="full-bleed"
           style="background: radial-gradient(60% 60% at 30% 30%, #38bdf822 0%, transparent 60%), linear-gradient(160deg,#0a1424 0%,#0b1728 50%,#060c16 100%);"></div>

      <!-- host audio: cloned-voice VO (root child) -->
      <audio id="vo" src="assets/promo-vo.wav" data-start="0" data-volume="1"></audio>

      <!-- service video clips (root children, muted, visibility by data-start/duration) -->
      <video id="v-express" class="fill-video" muted playsinline preload="auto"
             src="assets/svc-express-wash.mp4" data-start="8.8" data-duration="4.4" data-media-start="0"></video>
      <video id="v-hand" class="fill-video" muted playsinline preload="auto"
             src="assets/svc-hand-wash.mp4" data-start="13.0" data-duration="4.2" data-media-start="0"></video>
      <video id="v-ceramic" class="fill-video" muted playsinline preload="auto"
             src="assets/svc-ceramic-coating.mp4" data-start="17.0" data-duration="3.2" data-media-start="0"></video>

      <!-- readability scrim over the service montage -->
      <div id="scrim" class="clip full-bleed scrim-lr" data-start="8.8" data-duration="11.4" data-track-index="2"></div>

      <!-- ── Scene 1: title (0–4.4) ── -->
      <section id="s-title" class="clip scene" data-start="0" data-duration="4.2" data-track-index="3">
        <div id="t-eyebrow" class="eyebrow">San Fernando Valley</div>
        <div id="t-title" class="title">Prestige<br/>Car Wash</div>
        <div id="t-sub" class="sub">Hand wash · Detail · Ceramic</div>
      </section>

      <!-- ── Scene 2: the model (4.2–8.8) ── -->
      <section id="s-model" class="clip scene" data-start="4.2" data-duration="4.6" data-track-index="3">
        <div style="position:relative; display:inline-block;">
          <div id="m-head" class="title" style="font-size:104px;">No Appointments</div>
          <div id="m-strike" class="strike" style="width:0;"></div>
        </div>
        <div id="m-fcfs" class="sub" style="font-weight:800; font-size:56px; color:#38bdf8; margin-top:22px;">First Come · First Served</div>
        <div id="m-stats" class="row">
          <div><div id="m-6" class="stat">6</div><div class="statlbl">full lines</div></div>
          <div><div class="stat">Large</div><div class="statlbl">crew on deck</div></div>
          <div><div class="stat">0</div><div class="statlbl">wait to book</div></div>
        </div>
      </section>

      <!-- ── Scene 3: Express (8.8–13) ── -->
      <section id="s-express" class="clip scene left" data-start="8.8" data-duration="4.2" data-track-index="3">
        <div class="cat"><span style="width:10px;height:10px;border-radius:10px;background:#38bdf8;"></span> Wash</div>
        <div class="svc-name">Express Exterior Wash</div>
        <div id="p-express" class="price">$19</div>
      </section>

      <!-- ── Scene 4: Hand Wash (13–17) ── -->
      <section id="s-hand" class="clip scene left" data-start="13.0" data-duration="4.0" data-track-index="3">
        <div class="cat"><span style="width:10px;height:10px;border-radius:10px;background:#38bdf8;"></span> Signature</div>
        <div class="svc-name">Premium Hand Wash</div>
        <div id="p-hand" class="price">$79</div>
      </section>

      <!-- ── Scene 5: Ceramic (17–20.2) ── -->
      <section id="s-ceramic" class="clip scene left" data-start="17.0" data-duration="3.2" data-track-index="3">
        <div class="cat" style="background:rgba(52,211,153,.16);border-color:rgba(52,211,153,.45);color:#34d399;">
          <span style="width:10px;height:10px;border-radius:10px;background:#34d399;"></span> Protection</div>
        <div class="svc-name">Ceramic Coating · 9H</div>
        <div id="p-ceramic" class="price" style="color:#34d399;text-shadow:0 0 44px rgba(52,211,153,.5);">from $999</div>
      </section>

      <!-- ── Scene 6: Tips (20.2–24) ── -->
      <section id="s-tips" class="clip scene" data-start="20.2" data-duration="3.8" data-track-index="3">
        <div id="tip-head" class="title" style="font-size:80px;">Tip the crew directly</div>
        <div class="sub" style="margin-top:10px;">Scan their card — 100% goes straight to them.</div>
        <img id="tip-card" src="assets/tip-marco.png" style="height:520px; margin-top:26px; border-radius:22px; box-shadow:0 30px 90px rgba(0,0,0,.7);" />
      </section>

      <!-- ── Scene 7: CTA (24–28) ── -->
      <section id="s-cta" class="clip scene" data-start="24.0" data-duration="4.0" data-track-index="3">
        <div id="c-eyebrow" class="eyebrow" style="color:#34d399;">No appointment · 6 lines · just drive up</div>
        <div id="c-title" class="title" style="font-size:120px;">Come See Us</div>
        <div id="c-sub" class="sub" style="font-weight:800;">Prestige Car Wash</div>
      </section>
    </div>

    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });

      // shared background hue drift across the piece
      tl.to("#bg", { filter: "hue-rotate(-18deg)", duration: 8.8, ease: "sine.inOut" }, 8.8)
        .to("#bg", { filter: "hue-rotate(8deg)", duration: 7.8, ease: "sine.inOut" }, 20.2);

      // Scene 1 — title
      tl.from("#t-eyebrow", { opacity: 0, y: 20, duration: 0.5 }, 0.2)
        .from("#t-title",   { opacity: 0, y: 46, duration: 0.7, ease: "power3.out" }, 0.5)
        .from("#t-sub",     { opacity: 0, y: 20, duration: 0.5 }, 1.1);

      // Scene 2 — model
      tl.from("#m-head",  { opacity: 0, scale: 0.9, duration: 0.5, ease: "back.out(1.6)" }, 4.4)
        .to("#m-strike",  { width: 620, duration: 0.5, ease: "power2.out" }, 4.9)
        .from("#m-fcfs",  { opacity: 0, y: 18, duration: 0.5 }, 5.0)
        .from("#m-stats", { opacity: 0, y: 24, duration: 0.6 }, 5.6);

      // Service scenes — cat + name + price pop
      [["express", 8.8], ["hand", 13.0], ["ceramic", 17.0]].forEach(function (row) {
        var k = row[0], t = row[1];
        tl.from("#s-" + k + " .cat",      { opacity: 0, x: -30, duration: 0.4 }, t + 0.15)
          .from("#s-" + k + " .svc-name", { opacity: 0, y: 24, duration: 0.5 }, t + 0.3)
          .from("#p-" + k,                { opacity: 0, scale: 0.6, duration: 0.5, ease: "back.out(1.7)" }, t + 0.5);
      });

      // Scene 6 — tips
      tl.from("#tip-head", { opacity: 0, y: 20, duration: 0.5 }, 20.4)
        .from("#tip-card", { opacity: 0, y: 120, duration: 0.7, ease: "power3.out" }, 20.7);

      // Scene 7 — CTA
      tl.from("#c-eyebrow", { opacity: 0, y: 16, duration: 0.5 }, 24.2)
        .from("#c-title",   { opacity: 0, scale: 0.85, duration: 0.6, ease: "back.out(1.5)" }, 24.5)
        .from("#c-sub",     { opacity: 0, y: 16, duration: 0.5 }, 25.1);

      window.__timelines["main"] = tl;
    </script>
  </body>
</html>