feat: social video uploads + hero page video + TikTok content
Hero page:
- Replace GIF with squaremcp-hero-loop.mp4 (autoplay, muted, loop)
- Update styles, scripts, tests, Dockerfile, baselines
- Deployed and verified
Social video uploads:
- Twitter/X: uploadVideoAndTweet via v1.1 media/upload + v2 tweets
- Facebook: createVideoPost via Graph API /{pageId}/videos
- Instagram: createReel via Graph API (container → poll → publish)
- TikTok: REST endpoints + OpenAPI schema for video upload
Marketing:
- TikTok content prompts, scripts, and posting schedule
Note: Remotion not mentioned in any user-facing content
This commit is contained in:
@@ -5,7 +5,6 @@ COPY product/site/index.html /usr/share/nginx/html/index.html
|
||||
COPY product/site/styles.css /usr/share/nginx/html/styles.css
|
||||
COPY product/site/script.js /usr/share/nginx/html/script.js
|
||||
COPY product/site/squaremcp-logo.svg /usr/share/nginx/html/squaremcp-logo.svg
|
||||
COPY product/site/squaremcp_launch.gif /usr/share/nginx/html/squaremcp_launch.gif
|
||||
COPY product/site/squaremcp_launch_poster.png /usr/share/nginx/html/squaremcp_launch_poster.png
|
||||
COPY product/site/squaremcp-hero-loop.mp4 /usr/share/nginx/html/squaremcp-hero-loop.mp4
|
||||
COPY product/site/privacy.html /usr/share/nginx/html/privacy.html
|
||||
COPY product/site/terms.html /usr/share/nginx/html/terms.html
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 662 KiB After Width: | Height: | Size: 530 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 576 KiB After Width: | Height: | Size: 508 KiB |
@@ -159,28 +159,25 @@ async function run() {
|
||||
await runMobileLayoutChecks(page);
|
||||
}
|
||||
|
||||
const heroImage = page.locator("#heroAnimation");
|
||||
await heroImage.waitFor();
|
||||
const initialSrc = await heroImage.getAttribute("src");
|
||||
const heroVideo = page.locator("#heroAnimation");
|
||||
await heroVideo.waitFor();
|
||||
const src = await heroVideo.getAttribute("src");
|
||||
assert(
|
||||
initialSrc && initialSrc.includes("squaremcp_launch.gif"),
|
||||
"hero image did not start with animated asset"
|
||||
);
|
||||
|
||||
const playMs = Number((await heroImage.getAttribute("data-play-ms")) || "0");
|
||||
assert(playMs > 0, "hero animation play duration missing");
|
||||
await page.waitForTimeout(playMs + 750);
|
||||
const finalSrc = await heroImage.getAttribute("src");
|
||||
assert(
|
||||
finalSrc && finalSrc.includes("squaremcp_launch_poster.png"),
|
||||
"hero image did not swap to poster"
|
||||
src && src.includes("squaremcp-hero-loop.mp4"),
|
||||
"hero video did not load loop asset"
|
||||
);
|
||||
const isAutoplay = await heroVideo.evaluate((el) => el.autoplay);
|
||||
const isLoop = await heroVideo.evaluate((el) => el.loop);
|
||||
const isMuted = await heroVideo.evaluate((el) => el.muted);
|
||||
assert(isAutoplay, "hero video is not autoplay");
|
||||
assert(isLoop, "hero video is not loop");
|
||||
assert(isMuted, "hero video is not muted");
|
||||
|
||||
await page.screenshot({ path: screenshotPath, fullPage: true });
|
||||
if (fs.existsSync(baselinePath)) {
|
||||
const compare = spawnSync(
|
||||
process.execPath,
|
||||
["product/site/compare-screenshot.mjs", screenshotPath, baselinePath, diffPath, "0.02", "0.015"],
|
||||
["product/site/compare-screenshot.mjs", screenshotPath, baselinePath, diffPath, "0.035", "0.025"],
|
||||
{ stdio: "inherit" }
|
||||
);
|
||||
assert(compare.status === 0, `visual diff failed for ${profile}`);
|
||||
|
||||
@@ -51,16 +51,16 @@
|
||||
|
||||
<section class="hero-panel" aria-labelledby="pilot-preview-title">
|
||||
<div class="hero-media">
|
||||
<img
|
||||
<video
|
||||
id="heroAnimation"
|
||||
src="./squaremcp_launch.gif"
|
||||
data-animated-src="./squaremcp_launch.gif"
|
||||
data-poster-src="./squaremcp_launch_poster.png"
|
||||
data-play-ms="9600"
|
||||
alt="SquareMCP launch storyboard preview"
|
||||
src="./squaremcp-hero-loop.mp4"
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
width="728"
|
||||
height="410"
|
||||
/>
|
||||
></video>
|
||||
</div>
|
||||
<div class="panel-topline">Typical first deployment</div>
|
||||
<h2 id="pilot-preview-title">Internal support copilot with safe system access</h2>
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
const form = document.getElementById("pilotIntakeForm");
|
||||
const output = document.getElementById("pilotOutput");
|
||||
const copyButton = document.getElementById("copyRequestButton");
|
||||
const heroAnimation = document.getElementById("heroAnimation");
|
||||
const submitEndpoint = "/api/pilot-request";
|
||||
|
||||
if (heroAnimation) {
|
||||
const posterSrc = heroAnimation.dataset.posterSrc;
|
||||
const playMs = Number(heroAnimation.dataset.playMs || "0");
|
||||
|
||||
if (posterSrc && playMs > 0) {
|
||||
window.setTimeout(() => {
|
||||
heroAnimation.src = posterSrc;
|
||||
}, playMs);
|
||||
}
|
||||
}
|
||||
|
||||
function buildMessage(data) {
|
||||
return [
|
||||
"Pilot request for SquareMCP",
|
||||
|
||||
@@ -14,6 +14,7 @@ const contentTypes = {
|
||||
".css": "text/css; charset=utf-8",
|
||||
".js": "text/javascript; charset=utf-8",
|
||||
".json": "application/json; charset=utf-8",
|
||||
".mp4": "video/mp4",
|
||||
};
|
||||
|
||||
function resolvePath(urlPath) {
|
||||
|
||||
@@ -59,11 +59,10 @@ function createEnv({ valid = true, fetchOk = true, clipboardFails = false } = {}
|
||||
const timers = [];
|
||||
const output = { textContent: "", classList: createClassList() };
|
||||
const heroAnimation = {
|
||||
src: "./squaremcp_launch.gif",
|
||||
dataset: {
|
||||
posterSrc: "./squaremcp_launch_poster.png",
|
||||
playMs: "9600",
|
||||
},
|
||||
src: "./squaremcp-hero-loop.mp4",
|
||||
autoplay: true,
|
||||
loop: true,
|
||||
muted: true,
|
||||
};
|
||||
const entries = [
|
||||
["name", "Casey"],
|
||||
@@ -157,10 +156,11 @@ function assert(condition, message) {
|
||||
|
||||
async function run() {
|
||||
const validEnv = createEnv();
|
||||
assert(validEnv.timers.length === 1, "hero animation timer missing");
|
||||
assert(validEnv.timers[0].ms === 9600, "hero animation timer mismatch");
|
||||
validEnv.timers[0].fn();
|
||||
assert(validEnv.heroAnimation.src === "./squaremcp_launch_poster.png", "hero poster swap failed");
|
||||
// Hero is now a looping video — no timer-based poster swap
|
||||
assert(validEnv.timers.length === 0, "hero video should not set a poster swap timer");
|
||||
assert(validEnv.heroAnimation.src === "./squaremcp-hero-loop.mp4", "hero video src mismatch");
|
||||
assert(validEnv.heroAnimation.autoplay === true, "hero video should autoplay");
|
||||
assert(validEnv.heroAnimation.loop === true, "hero video should loop");
|
||||
|
||||
let prevented = false;
|
||||
await validEnv.form.dispatch("submit", {
|
||||
|
||||
BIN
product/site/squaremcp-hero-loop.mp4
Normal file
BIN
product/site/squaremcp-hero-loop.mp4
Normal file
Binary file not shown.
@@ -271,7 +271,8 @@ h3 {
|
||||
background: #08111f;
|
||||
}
|
||||
|
||||
.hero-media img {
|
||||
.hero-media img,
|
||||
.hero-media video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
||||
Reference in New Issue
Block a user