● Zion Boggan
repos/Stepping App/promo/record.mjs
zionboggan.com ↗
71 lines · javascript
History for this file →
1
import { chromium } from "playwright-core";
2
import { readFileSync, readdirSync, renameSync, mkdirSync } from "fs";
3
 
4
const EXE = "/root/.npm/_npx/361ceb562f3b3235/node_modules/playwright-core/.local-browsers/chromium-1228/chrome-linux64/chrome";
5
const SCR = "/tmp/claude-0/-shared-projects/26d7af11-61c4-4183-85c3-70d9aac72ef6/scratchpad";
6
const REC = "/shared/projects/SteppingApp/promo/rec";
7
const BASE = "http://REDACTED-IP:3000";
8
const DJ = readFileSync(`${SCR}/.djid`, "utf8").trim();
9
const EV = readFileSync(`${SCR}/.evid`, "utf8").trim();
10
 
11
const scenes = [
12
  { id: "s1", url: "/", vp: [1920, 1080], dur: 11.3, act: "hero" },
13
  { id: "s2", url: "/", vp: [1920, 1080], dur: 7.45, act: "toRoute" },
14
  { id: "s3", url: "/city/atlanta", vp: [1920, 1080], dur: 12.15, act: "scroll" },
15
  { id: "s4", url: `/city/atlanta/event/${EV}`, vp: [1920, 1080], dur: 8.18, act: "scroll" },
16
  { id: "s5", url: "/city/atlanta/yard", vp: [1920, 1080], dur: 11.3, act: "scroll" },
17
  { id: "s6", url: `/city/atlanta/profile/dj/${DJ}`, vp: [1920, 1080], dur: 5.55, act: "hold" },
18
  { id: "s7", url: "/city/atlanta/route", vp: [1920, 1080], dur: 11.5, act: "scroll" },
19
  { id: "s8", url: "/", vp: [430, 932], dur: 10.25, act: "scroll", mobile: true },
20
  { id: "s9", url: "/", vp: [1920, 1080], dur: 9.2, act: "hero" },
21
];
22
 
23
const args = ["--no-sandbox", "--disable-dev-shm-usage", "--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", "--ignore-gpu-blocklist"];
24
const browser = await chromium.launch({ executablePath: EXE, args });
25
 
26
for (const s of scenes) {
27
  const dir = `${REC}/${s.id}`;
28
  mkdirSync(dir, { recursive: true });
29
  const ctx = await browser.newContext({
30
    viewport: { width: s.vp[0], height: s.vp[1] },
31
    deviceScaleFactor: 1,
32
    recordVideo: { dir, size: { width: s.vp[0], height: s.vp[1] } },
33
    ...(s.mobile ? { isMobile: true, hasTouch: true } : {}),
34
  });
35
  const page = await ctx.newPage();
36
  await page.goto(`${BASE}${s.url}`, { waitUntil: "networkidle" });
37
  await page.waitForTimeout(s.act === "hero" ? 1800 : 900);
38
  const ms = s.dur * 1000;
39
 
40
  if (s.act === "hero") {
41
    const [W, H] = s.vp;
42
    const pts = [[W * 0.6, H * 0.42], [W * 0.72, H * 0.55], [W * 0.54, H * 0.5], [W * 0.68, H * 0.46]];
43
    const per = ms / pts.length;
44
    for (const [x, y] of pts) {
45
      await page.mouse.move(x, y, { steps: 24 });
46
      await page.mouse.click(x, y);
47
      await page.waitForTimeout(Math.max(per - 250, 200));
48
    }
49
  } else if (s.act === "toRoute") {
50
    await page.evaluate(() => {
51
      const l = window.__lenis; const el = document.querySelector("#route");
52
      if (el && l) l.scrollTo(el.offsetTop - 90, { duration: 4.5 });
53
    });
54
    await page.waitForTimeout(ms);
55
  } else if (s.act === "scroll") {
56
    await page.evaluate((d) => {
57
      const l = window.__lenis; const t = document.body.scrollHeight - window.innerHeight;
58
      if (l) l.scrollTo(t, { duration: d }); else window.scrollTo({ top: t, behavior: "smooth" });
59
    }, s.dur - 1.5);
60
    await page.waitForTimeout(ms);
61
  } else {
62
    await page.waitForTimeout(ms);
63
  }
64
 
65
  await ctx.close();
66
  const f = readdirSync(dir).find((x) => x.endsWith(".webm"));
67
  renameSync(`${dir}/${f}`, `${REC}/${s.id}.webm`);
68
  console.log(s.id, "recorded");
69
}
70
await browser.close();
71
console.log("ALL RECORDED");