Meta Description" name="description" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
<title>Zynga Winter Assets Ad</title>
<script src="mraid.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
-webkit-user-select: none;
user-select: none;
}
body {
display: flex;
justify-content: center;
align-items: center;
background: #000;
}
#ad-container {
position: relative;
width: 100%;
height: 100%;
max-width: 100vw;
max-height: 100vh;
overflow: hidden;
cursor: pointer;
}
/* Intro Screen */
#intro-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #9fd7ff, #e9f6ff);
z-index: 10;
opacity: 1;
transition: opacity 0.3s ease;
pointer-events: auto;
overflow: hidden;
}
#intro-screen.hidden {
opacity: 0;
pointer-events: none;
}
#intro-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
#intro-rgb-video {
width: 100%;
height: 100%;
display: block;
object-fit: contain;
-webkit-mask-image: radial-gradient(ellipse 85% 85% at 50% 50%, black 0%, black 70%, transparent 100%);
mask-image: radial-gradient(ellipse 85% 85% at 50% 50%, black 0%, black 70%, transparent 100%);
}
#intro-tint-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 8;
pointer-events: none;
opacity: 1;
transition: opacity 0.5s ease;
}
#intro-tint-overlay.fade-out {
opacity: 0;
}
/* Video Container */
#video-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
display: none;
z-index: 5;
overflow: hidden;
}
#ad-video {
width: 100%;
height: 100%;
display: block;
object-fit: contain;
}
/* Frame Overlays */
#video-frame-overlay-bottom {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 6;
pointer-events: auto;
opacity: 1;
transition: opacity 0.3s ease;
cursor: pointer;
object-fit: contain;
}
#video-frame-overlay-bottom.hidden {
opacity: 0;
pointer-events: none;
}
#video-frame-overlay-top {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 7;
pointer-events: auto;
opacity: 1;
transition: opacity 0.3s ease;
cursor: pointer;
object-fit: contain;
}
#video-frame-overlay-top.hidden {
opacity: 0;
pointer-events: none;
}
/* End Card */
#end-card {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
z-index: 6;
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
cursor: pointer;
display: none;
}
#end-card.visible {
opacity: 1;
pointer-events: auto;
display: block;
}
#end-card-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 7;
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
cursor: pointer;
object-fit: contain;
display: none;
}
#end-card-overlay.visible {
opacity: 1;
pointer-events: auto;
display: block;
}
/* Mute Button */
#mute-button {
position: absolute;
top: 3%;
right: 3%;
width: 60px;
height: 60px;
background-color: rgba(0, 0, 0, 0.6);
border: none;
border-radius: 50%;
cursor: pointer;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
transition: background-color 0.3s ease, opacity 0.5s ease;
-webkit-appearance: none;
appearance: none;
-webkit-tap-highlight-color: transparent;
}
#mute-button:active {
background-color: rgba(0, 0, 0, 0.8);
}
#mute-button.hidden {
opacity: 0;
pointer-events: none;
}
#mute-button svg {
width: 50%;
height: 50%;
fill: white;
pointer-events: none;
}
/* Back Button */
#back-button {
position: absolute;
top: 3%;
left: 3%;
width: 60px;
height: 60px;
background-color: rgba(0, 0, 0, 0.6);
border: none;
border-radius: 50%;
cursor: pointer;
z-index: 100;
display: none;
justify-content: center;
align-items: center;
transition: background-color 0.3s ease, opacity 0.5s ease;
-webkit-appearance: none;
appearance: none;
-webkit-tap-highlight-color: transparent;
}
#back-button:active {
background-color: rgba(0, 0, 0, 0.8);
}
#back-button.hidden {
opacity: 0;
pointer-events: none;
}
#back-button svg {
width: 50%;
height: 50%;
fill: white;
pointer-events: none;
}
/* Progress Bar */
#progress-bar {
position: fixed;
bottom: 0;
left: 0;
height: 3px;
background-color: #4CAF50;
width: 0%;
z-index: 99;
transition: width 0.1s linear;
}
/* Responsive */
@media screen and (orientation: landscape) {
#mute-button, #back-button {
width: 50px;
height: 50px;
}
#mute-button svg, #back-button svg {
width: 45%;
height: 45%;
}
}
</style>
</head>
<body>
<div id="ad-container">
<!-- Intro Screen -->
<div id="intro-screen">
<div id="intro-container">
<video
id="intro-rgb-video"
muted
playsinline
webkit-playsinline
preload="auto"
crossorigin="anonymous">
<source src="https://zap.cdn.zynga.com/customassets/production/3367e48a845a6cc329b75b9bd0c1ce321cfced2827d6971ebb25dd3e33cd13d1.mp4" type="video/mp4">
</video>
</div>
</div>
<div id="intro-tint-overlay"></div>
<!-- Video Container -->
<div id="video-container">
<button id="mute-button" aria-label="Toggle mute">
<svg viewBox="0 0 24 24">
<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>
</svg>
</button>
<button id="back-button" aria-label="Go back">
<svg viewBox="0 0 24 24">
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/>
</svg>
</button>
<video id="ad-video" playsinline webkit-playsinline preload="auto" muted>
<source src="https://zap.cdn.zynga.com/customassets/production/5e70bb590acfb56ac3be748402af273f221b728fd2badcb9136e3accf591f4f7.mp4#t=0.01" type="video/mp4">
</video>
<img
id="end-card"
src="https://zap.cdn.zynga.com/customassets/production/72ca9fc97a5691dca7179fdbace700c816e9c491bcd7db83a56b5c90f509f8b6.jpg"
alt="End Card" />
<div id="progress-bar"></div>
</div>
<!-- Frame Overlays -->
<img
id="video-frame-overlay-bottom"
src="https://zap.cdn.zynga.com/customassets/production/d9f04be88349a258e00919683aaf25fe2adf55811c584780fffe041350de0230.gif"
alt="Video Frame Overlay Bottom" />
<img
id="video-frame-overlay-top"
src="https://zap.cdn.zynga.com/customassets/production/102aa11cc95c8f8ab0c8c8bf05ce84dda58f47d26dd2cb69e263fa90cba97c8e.gif"
alt="Video Frame Overlay Top" />
<img
id="end-card-overlay"
src="https://zap.cdn.zynga.com/customassets/production/ff3d92c87a390d149b0823d02a308b2c4105a1394c156ec2b0d886c98dcf2613.png"
alt="End Card Overlay" />
</div>
<script>
// Platform detection
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
const isAndroid = /Android/.test(navigator.userAgent);
// DOM elements
const adContainer = document.getElementById('ad-container');
const introScreen = document.getElementById('intro-screen');
const videoContainer = document.getElementById('video-container');
const video = document.getElementById('ad-video');
const muteButton = document.getElementById('mute-button');
const backButton = document.getElementById('back-button');
const introContainer = document.getElementById('intro-container');
const introTintOverlay = document.getElementById('intro-tint-overlay');
const introRgbVideo = document.getElementById('intro-rgb-video');
const videoFrameOverlayBottom = document.getElementById('video-frame-overlay-bottom');
const videoFrameOverlayTop = document.getElementById('video-frame-overlay-top');
const endCard = document.getElementById('end-card');
const endCardOverlay = document.getElementById('end-card-overlay');
const progressBar = document.getElementById('progress-bar');
// Configuration
const clickOutUrl = 'https://app.appsflyer.com/id653508448?pid=CentralXP-Test&c=xPromo_WinterFrameTest&af_adset=%%AD_SLOT_NAME%%&af_ad=%%CREATIVE_NAME%%';
const INTRO_DURATION = 2500;
const CLOSE_BUTTON_DELAY = 7500;
// State
let introStarted = false;
let compositeRunning = false;
let videoReady = false;
let isVideoPlaying = false;
let videoStarted = false;
let isShowingEndcard = false;
let adStarted = false;
let introTimerId = null;
let closeButtonTimer = null;
function startComposite() {
if (compositeRunning || introStarted) return;
introStarted = true;
compositeRunning = true;
adStarted = true;
introRgbVideo.currentTime = 0;
console.log('Starting intro video...');
introRgbVideo.play().catch(e => {
console.warn('Intro video play error:', e);
}).then(() => {
console.log('Intro video playing');
scheduleIntroCutoff();
});
// Schedule close button appearance
closeButtonTimer = setTimeout(() => {
muteButton.style.display = 'flex';
}, CLOSE_BUTTON_DELAY);
}
function scheduleIntroCutoff() {
introTimerId = setTimeout(() => {
console.log('Intro cut off');
compositeRunning = false;
introTintOverlay.classList.add('fade-out');
introScreen.classList.add('hidden');
introRgbVideo.pause();
}, INTRO_DURATION);
}
// Video ready detection
introRgbVideo.addEventListener("canplay", () => {
videoReady = true;
console.log('Intro video can play');
if (!compositeRunning && !introStarted) {
startComposite();
}
});
introRgbVideo.addEventListener("loadedmetadata", () => {
console.log('Intro video metadata loaded');
if (!compositeRunning && !introStarted) {
startComposite();
}
});
// Aggressive fallbacks for autoplay
setTimeout(() => {
if (!introStarted) {
console.log('Fallback 1: Starting composite (500ms)');
startComposite();
}
}, 500);
setTimeout(() => {
if (!introStarted) {
console.log('Fallback 2: FORCING START (1500ms)');
startComposite();
}
}, 1500);
// Initialize intro video
introRgbVideo.preload = 'auto';
introRgbVideo.load();
introRgbVideo.play().catch(() => {
console.log('Intro autoplay blocked');
});
// Video handling
function playVideo() {
if (isVideoPlaying || isShowingEndcard) return;
isVideoPlaying = true;
videoStarted = true;
introScreen.classList.add('hidden');
videoContainer.style.display = 'block';
backButton.style.display = 'flex';
muteButton.style.display = 'flex';
video.load();
video.play().catch(error => {
console.error("Failed to play video:", error);
isVideoPlaying = false;
});
}
function goBackToIntro() {
isVideoPlaying = false;
isShowingEndcard = false;
videoStarted = false;
videoContainer.style.display = 'none';
introScreen.classList.remove('hidden');
video.pause();
video.currentTime = 0;
progressBar.style.width = '0%';
backButton.style.display = 'none';
endCard.classList.remove('visible');
endCardOverlay.classList.remove('visible');
}
function showEndcard() {
isShowingEndcard = true;
isVideoPlaying = false;
video.pause();
video.currentTime = video.duration;
endCard.classList.add('visible');
endCardOverlay.classList.add('visible');
videoFrameOverlayBottom.classList.add('hidden');
videoFrameOverlayTop.classList.add('hidden');
muteButton.classList.add('hidden');
progressBar.style.width = '100%';
}
function handleClick() {
if (typeof mraid !== 'undefined' && mraid.open) {
mraid.open(clickOutUrl);
} else {
window.open(clickOutUrl, '_blank');
}
}
// Click handlers
adContainer.addEventListener('click', (e) => {
if (e.target === muteButton || muteButton.contains(e.target)) return;
if (e.target === backButton || backButton.contains(e.target)) return;
if (introScreen.classList.contains('hidden') && !isShowingEndcard) {
handleClick();
}
});
videoContainer.addEventListener('click', (e) => {
if (e.target === muteButton || muteButton.contains(e.target)) return;
if (e.target === backButton || backButton.contains(e.target)) return;
handleClick();
});
endCard.addEventListener('click', handleClick);
endCardOverlay.addEventListener('click', handleClick);
videoFrameOverlayBottom.addEventListener('click', handleClick);
videoFrameOverlayTop.addEventListener('click', handleClick);
muteButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
video.muted = !video.muted;
updateMuteButtonIcon();
});
backButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
goBackToIntro();
});
introScreen.addEventListener('click', () => {
if (!isVideoPlaying) {
playVideo();
}
});
function updateMuteButtonIcon() {
if (video.muted) {
muteButton.innerHTML = '<svg viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>';
} else {
muteButton.innerHTML = '<svg viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>';
}
}
// Video events
video.addEventListener('timeupdate', () => {
const progress = (video.currentTime / video.duration) * 100;
progressBar.style.width = progress + '%';
});
video.addEventListener('ended', () => {
showEndcard();
});
// MRAID integration
if (typeof mraid !== 'undefined') {
if (mraid.getState() === 'loading') {
mraid.addEventListener('ready', () => {
mraid.notifyViewableChange(true);
});
} else {
mraid.notifyViewableChange(true);
}
mraid.addEventListener('viewableChange', (viewable) => {
if (viewable && !adStarted) {
startComposite();
}
});
mraid.addEventListener('stateChange', (state) => {
console.log('MRAID state changed:', state);
});
mraid.addEventListener('error', (message) => {
console.error('MRAID error:', message);
});
} else {
// Fallback for testing
setTimeout(startComposite, 500);
}
// Handle visibility changes
document.addEventListener('visibilitychange', () => {
if (!document.hidden && videoStarted && !isShowingEndcard) {
video.play().catch(e => console.warn('Resume play error:', e));
} else if (document.hidden && videoStarted) {
video.pause();
}
});
</script>
</body>
</html> 12
2
6821KB
6827KB
124.0ms
296.0ms
1,700.0ms