diff --git a/.gitignore b/.gitignore index f9e0f3e..c10bac5 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ next-env.d.ts # store screenshot artifacts /scripts/shots/ /store-assets/ +/scripts/promo/ diff --git a/scripts/promo.js b/scripts/promo.js new file mode 100644 index 0000000..1f20452 --- /dev/null +++ b/scripts/promo.js @@ -0,0 +1,100 @@ +// Build an animated portrait promo from the captured screenshots and record it +// to webm with Playwright. (ffmpeg then encodes it to mp4 — see the run step.) +const { chromium } = require("playwright"); +const fs = require("fs"); +const path = require("path"); + +const ASSETS = path.join(__dirname, "..", "store-assets"); +const OUT = path.join(__dirname, "promo"); +fs.mkdirSync(OUT, { recursive: true }); + +const b64 = (f) => "data:image/png;base64," + fs.readFileSync(path.join(ASSETS, f)).toString("base64"); +const icon = b64("icon-512.png"); + +// type: intro | slide | outro +const SLIDES = [ + { type: "intro", title: "برگ وسط", sub: "بازی حکم آنلاین ایرانی" }, + { type: "slide", img: b64("01-home.png"), cap: "سه حالت بازی در یک اپ" }, + { type: "slide", img: b64("06-game.png"), cap: "حکمِ واقعی، کارت‌های زیبا" }, + { type: "slide", img: b64("02-leaderboard.png"), cap: "در لیگ‌ها بالا برو و رکورد بزن" }, + { type: "slide", img: b64("04-shop.png"), cap: "آواتار و آیتم‌های ویژه" }, + { type: "slide", img: b64("03-achievements.png"), cap: "دستاوردها و جایزه‌ی روزانه" }, + { type: "slide", img: b64("05-profile.png"), cap: "پروفایل کامل خودت را بساز" }, + { type: "outro", title: "همین حالا رایگان نصب کن!", sub: "برگ وسط", icon: true }, +]; +const DUR = 2600; // ms per slide +const FADE = 700; + +const slideHtml = (s, i) => { + if (s.type === "intro" || s.type === "outro") + return `
+ +
${s.title}
+
${s.sub}
+
`; + return `
+
برگ وسط
+
+
${s.cap}
+
`; +}; + +const html = ` + +
${SLIDES.map(slideHtml).join("")}
+ +`; + +(async () => { + const total = SLIDES.length * DUR + 1200; + const browser = await chromium.launch({ channel: "chrome" }); + const ctx = await browser.newContext({ + viewport: { width: 1080, height: 1920 }, + deviceScaleFactor: 1, + recordVideo: { dir: OUT, size: { width: 1080, height: 1920 } }, + }); + const page = await ctx.newPage(); + await page.setContent(html, { waitUntil: "networkidle" }); + await page.waitForTimeout(total); + const video = page.video(); + await ctx.close(); // finalizes the recording + const p = await video.path(); + await browser.close(); + console.log("VIDEO:" + p); +})().catch((e) => { console.error("FATAL", e); process.exit(1); });